package com.starlink.service.impl;

import cn.hutool.core.util.NumberUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import cn.hutool.core.convert.Convert;
import com.github.pagehelper.PageInfo;
import com.github.pagehelper.PageHelper;
import com.google.common.collect.Lists;
import com.lop.open.api.sdk.domain.ECAP.CommonCreateOrderApi.commonCreateOrderV1.CommonCreateOrderResponse;
import com.lop.open.api.sdk.domain.ECAP.CommonQueryOrderApi.commonGetOrderTraceV1.CommonOrderTraceDetail;
import com.lop.open.api.sdk.domain.ECAP.CommonQueryOrderApi.commonGetOrderTraceV1.CommonOrderTraceResponse;
import com.lop.open.api.sdk.domain.ECAP.CommonSubscribeTraceApi.commonSubscribeTraceV1.Response;
import com.lop.open.api.sdk.domain.jdcloudprint.PullDataService.pullData.PrePrintDataInfo;
import com.starlink.client.jd.JdClient;
import com.starlink.client.jd.properties.JdProperties;
import com.starlink.client.jd.request.*;
import com.starlink.client.jd.request.base.CommonCargoInfo;
import com.starlink.client.jd.request.base.CommonProductInfo;
import com.starlink.client.jd.request.base.Contact;
import com.starlink.client.jd.request.base.WayBillInfoRequest;
import com.starlink.client.jd.vo.PrintContentsVO;
import com.starlink.client.jd.vo.PrintPullDataVO;
import com.starlink.common.annotation.client.WeixinJsClient;
import com.starlink.common.annotation.client.base.RefundAmount;
import com.starlink.common.annotation.client.weixin.*;
import com.starlink.common.config.WechatConfigurationConfig;
import com.starlink.common.enums.*;
import com.starlink.common.exception.BusinessException;
import com.starlink.common.utils.AssertUtil;
import com.starlink.context.SessionContext;
import com.starlink.mapper.*;
import com.starlink.model.domain.*;
import com.starlink.model.dtomapper.MallBooksOrderDtoMapper;
import com.starlink.model.dtomapper.MallIntegrationOrderDtoMapper;
import com.starlink.model.request.*;
import com.starlink.model.request.mall.*;
import com.starlink.model.util.MallBooksOrderConvert;
import com.starlink.model.vo.*;
import com.starlink.model.vo.book.*;
import com.starlink.model.vo.mall.*;
import com.starlink.service.*;
import com.starlink.utils.IRedisCacheService;
import com.starlink.utils.MoneyUtil;
import com.starlink.utils.OrderNumUtil;
import com.starlink.utils.WeixinUtil;
import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import static com.starlink.common.enums.AcquireModeEnum.*;
import static com.starlink.common.enums.ActionTypeEum.*;
import static com.starlink.common.enums.BooleanEnum.TRUE;
import static com.starlink.common.enums.FreeEnum.FA_HUO_SHIPING;
import static com.starlink.common.enums.OrderStatusEnum.*;
import static com.starlink.common.enums.OrderStatusEnum.DONE;
import static com.starlink.common.enums.OrderTypeEnum.*;
import static com.starlink.common.enums.PaymentTypeEnum.JI_FEN_MONEY_PAY;
import static com.starlink.common.enums.PaymentTypeEnum.JI_FEN_PAY;
import static com.starlink.common.enums.RedisHashKeyEnum.CAR_ORDER_PRODUCT_IDS;
import static com.starlink.common.enums.RedisHashKeyEnum.ORDER_REFUND;
import static com.starlink.utils.IDUtils.getId;
import static com.starlink.utils.PageUtils.getOrderBy;
import static java.math.BigDecimal.ZERO;

import java.io.ByteArrayInputStream;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.SignatureException;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author zhanghong
 */
@Slf4j
@Service
public class MallOrderServiceImpl extends ServiceImpl<MallBooksOrderMapper, MallBooksOrderDO> implements MallOrderService {
    @Autowired
    private MallBooksOrderMapper mallBooksOrderMapper;
    @Autowired
    private MallPeripheryOrderMapper peripheryOrderMapper;
    @Autowired
    private ShoppingCartOrderMapper cartOrderManager;
    @Autowired
    private AddressService addressService;
    @Autowired
    private MallBooksService bookService;
    @Autowired
    private FreeTemplateService templateService;
    @Autowired
    private MallBooksSpecificationService specificationService;
    @Autowired
    private MallPeripherySpecificationService peripherySpecificationService;
    @Autowired
    private ShoppingCartDetailService cartDetailService;
    @Autowired
    private MallOrderDetailsService orderDetailsService;
    @Autowired
    private MallPeripheryOrderService periodService;
    @Autowired
    private MallPeripheryOrderDetailsService periodsService;
    @Autowired
    private ShoppingCartOrderService cartOrderService;
    @Autowired
    private ShoppingCartOrderDetailsService cartOrderDetailsService;
    @Autowired
    private WeixinJsClient weixinJsClient;
    @Autowired
    private MallPeripheryService peripheryService;
    @Autowired
    private MallRefundsMapper refundsMapper;
    @Autowired
    private IRedisCacheService redisCacheService;
    @Autowired
    private MallPaymentService paymentService;
    @Autowired
    private PointsService pointsService;
    @Autowired
    private MallIntegrationService integrationService;
    @Autowired
    private MallIntegrationOrderService integrationOrderService;
    @Autowired
    private MallIntegrationOrderMapper mallIntegrationOrderMapper;
    @Autowired
    private MallBooksRasService rasService;
    @Autowired
    private MallLogisticsService logisticsService;
    @Autowired
    private JdClient jdClient;
    @Autowired
    private JdProperties jdProperties;
    @Autowired
    private FreeDeliverySetService freeDeliverySetService;
    @Autowired
    private AdminAddressService adminAddressService;

    private static final long EXPIRE_SECONDS = 7 * 24 * 60 * 60; // 过期时间，单位：秒

    @Override
    public MallBooksOrderVO getByKey(long id) {
        MallBooksOrderVO mallBooksOrderVO = MallBooksOrderDtoMapper.INSTANCE.do2VO(getById(id));
        return mallBooksOrderVO;
    }

    @Override
    public PageInfo<MallBooksOrderVO> pageQuery(Pageable pageable, MallBooksOrderRequest request) {
        PageHelper.startPage(request.getPageNum(), request.getPageSize(), getOrderBy(pageable.getSort())).setReasonable(true);
        List<MallBooksOrderDO> list = mallBooksOrderMapper.pageQuery(request, request.getPageSize(), request.fetchOffSet());
        List<MallBooksOrderVO> mallBooksOrderVOList = MallBooksOrderConvert.buildMallBooksOrderVoList(list);
        return new PageInfo(mallBooksOrderVOList);
    }

    @Override
    public List<MallBooksOrderVO> listQuery(MallBooksOrderRequest request) {
        List<MallBooksOrderDO> list = mallBooksOrderMapper.selectDOList(MallBooksOrderDtoMapper.INSTANCE.request2DO(request));
        List<MallBooksOrderVO> mallBooksOrderVOS = MallBooksOrderConvert.buildMallBooksOrderVoList(list);
        return mallBooksOrderVOS;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean add(MallBooksOrderRequest request) {
        request.setId(getId());
        save(MallBooksOrderDtoMapper.INSTANCE.request2DO(request));
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateByKey(MallBooksOrderRequest request) {
        AssertUtil.assertNotNull(request.getId(), "id不能为空");
        saveOrUpdate(MallBooksOrderDtoMapper.INSTANCE.request2DO(request));
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteDOByIds(String ids) {
        mallBooksOrderMapper.deleteDOByIds(Convert.toStrArray(ids));
        return true;
    }

    @Override
    public MallArticlesBuyVO selectBuy(MallBuyRequest request) {
        //是否是vip 0否 1是
        Boolean isVip = SessionContext.getWechatUserInfo().getVip() == 1 ? true : false;
        Long userId = SessionContext.getWechatUserId();
        Integer articlesCategory = request.getArticlesCategory();
        Long articlesId = request.getArticlesId();
        Long specificationId = request.getSpecificationId();
        Integer quantity = request.getQuantity();
        MallArticlesBuyVO buyVO = new MallArticlesBuyVO();
        buyVO.setIsVip(isVip);
        buyVO.setIsUp(false);
        AddressRequest addressRequest = new AddressRequest();
        addressRequest.setCreateUser(userId);
        List<AddressVO> addressVOS = addressService.listQuery(addressRequest);
        if (CollectionUtils.isNotEmpty(addressVOS)) {
            List<AddressBuyVO> addressBuyVOS = addressVOS.stream().map(item -> {
                AddressBuyVO addressBuyVO = new AddressBuyVO();
                addressBuyVO.setReceiverId(item.getId());
                addressBuyVO.setReceiver(item.getReceiver());
                addressBuyVO.setMobile(item.getMobile());
                addressBuyVO.setProvince(item.getProvince());
                addressBuyVO.setCity(item.getCity());
                addressBuyVO.setArea(item.getArea());
                addressBuyVO.setDetail(item.getDetail());
                addressBuyVO.setDefaultAddr(item.getDefaultAddr());
                return addressBuyVO;
            }).collect(Collectors.toList());
            buyVO.setAddresses(addressBuyVOS);
        }
        BigDecimal price;
        BigDecimal vipPrice;
        if (request.getCarId() != null) {
            AtomicReference<BigDecimal> amount = new AtomicReference(new BigDecimal(0));
            AtomicReference<BigDecimal> vipAmount = new AtomicReference(new BigDecimal(0));
            List<ShoppingCartDetailVO> cartDetailList = cartDetailService.selectList(request.getCarId());
            Map<Long, Long> carData = request.getCarData();
            List<MallArticlesVO> list = new ArrayList<>(carData.size());
            cartDetailList.stream().forEach(item -> {
                Long id = item.getArticlesId();
                Long num = carData.get(id);
                if (num!=null) {
                    MallArticlesVO articlesVO = new MallArticlesVO();
                    BigDecimal price1 = item.getPrice();
                    BigDecimal vipPrice1 = item.getVipPrice();
                    if (isVip){
                        if (vipPrice1!=null){
                            vipAmount.set(vipAmount.get().add(new BigDecimal(num).multiply(vipPrice1)));
                            articlesVO.setPrice(vipPrice1);
                        }else {
                            vipAmount.set(vipAmount.get().add(new BigDecimal(num).multiply(price1)));
                            articlesVO.setPrice(price1);
                        }
                    }else {
                        amount.set(amount.get().add(new BigDecimal(num).multiply(price1)));
                        articlesVO.setPrice(price1);
                    }
                    //查询商品基本信息
                    articlesVO.setArticlesCategory(BOOK.getType());
                    articlesVO.setQuantity(num.intValue());
                    articlesVO.setSpecification(item.getSpecification());
                    articlesVO.setPicture(item.getPicture());
                    articlesVO.setTitle(item.getTitle());
                    articlesVO.setArticlesId(id);
                    list.add(articlesVO);
                }
            });
            if (isVip){
                buyVO.setAmount(vipAmount.get());
            }else {
                buyVO.setAmount(amount.get());
            }
            buyVO.setAllArticles(list);
        } else {
            if (BOOK.getType().equals(articlesCategory)) {
                MallArticlesVO articlesVO = new MallArticlesVO();
                //计算商品总价
                MallBooksSpecificationVO specificationVO = specificationService.getByKey(specificationId);
                price = specificationVO.getPrice();
                vipPrice = specificationVO.getVipPrice();
                if (isVip){
                    if (vipPrice!=null) {
                        BigDecimal vipMount = vipPrice.multiply(new BigDecimal(quantity)).setScale(2);
                        buyVO.setAmount(vipMount);
                        articlesVO.setPrice(vipPrice);
                    }else {
                        BigDecimal mount = price.multiply(new BigDecimal(quantity)).setScale(2);
                        buyVO.setAmount(mount);
                        articlesVO.setPrice(price);
                    }
                }else {
                    BigDecimal mount = price.multiply(new BigDecimal(quantity)).setScale(2);
                    buyVO.setAmount(mount);
                    articlesVO.setPrice(price);
                }
                //查询商品信息
                MallBooksVO booksVO = bookService.getByKey(articlesId);
                articlesVO.setArticlesCategory(BOOK.getType());
                articlesVO.setQuantity(quantity);
                articlesVO.setPicture(booksVO.getPicture());
                articlesVO.setTitle(booksVO.getTitle());
                articlesVO.setArticlesId(articlesId);
                articlesVO.setFreeTemplateId(booksVO.getFreeTemplateId());
                List<MallArticlesVO> mallBooksVOS = Arrays.asList(articlesVO);
                buyVO.setAllArticles(mallBooksVOS);
            }
            if (OrderTypeEnum.RIM.getType().equals(articlesCategory)) {
                MallArticlesVO articlesVO = new MallArticlesVO();
                //计算商品总价
                MallPeripherySpecificationVO specificationVO = peripherySpecificationService.getByKey(specificationId);
                price = specificationVO.getPrice();
                vipPrice = specificationVO.getVipPrice();
                if (isVip){
                    if (vipPrice!=null) {
                        BigDecimal vipMount = vipPrice.multiply(new BigDecimal(quantity)).setScale(2);
                        buyVO.setAmount(vipMount);
                        articlesVO.setPrice(vipPrice);
                    }else {
                        BigDecimal mount = price.multiply(new BigDecimal(quantity)).setScale(2);
                        buyVO.setAmount(mount);
                        articlesVO.setPrice(price);
                    }
                }else {
                    BigDecimal mount = price.multiply(new BigDecimal(quantity)).setScale(2);
                    buyVO.setAmount(mount);
                    articlesVO.setPrice(price);
                }
                //查询商品信息
                MallPeripheryVO peripheryVO = peripheryService.getByKey(articlesId);
                articlesVO.setArticlesCategory(RIM.getType());
                articlesVO.setQuantity(quantity);
                articlesVO.setPicture(peripheryVO.getPicture());
                articlesVO.setTitle(peripheryVO.getName());
                articlesVO.setArticlesId(articlesId);
                articlesVO.setFreeTemplateId(peripheryVO.getFreeTemplateId());
                List<MallArticlesVO> mallBooksVOS = Arrays.asList(articlesVO);
                buyVO.setAllArticles(mallBooksVOS);
            }
        }
        return buyVO;
    }

    @Override
    public MallArticlesBuyVO checkInventory(MallBuyRequest request) {
        //是否是vip 0否 1是
        UserVO wechatUserInfo = SessionContext.getWechatUserInfo();
        Boolean isVip = false;
        if (wechatUserInfo.getVip()!=null){
            isVip = wechatUserInfo.getVip() == 1 ? true : false;
        }
        Integer articlesCategory = request.getArticlesCategory();
        Long specificationId = request.getSpecificationId();
        Integer quantity = request.getQuantity();
        Long articlesId = request.getArticlesId();
        if (quantity != null && quantity < 0) {
            throw new RuntimeException("商品数量不能小于0!");
        }
        MallArticlesBuyVO buyVO = new MallArticlesBuyVO();
        buyVO.setIsVip(isVip);
        buyVO.setIsUp(false);
        Long inventory;//库存
        if (request.getCarId() != null) {
            List<ShoppingCartDetailVO> cartDetailList = cartDetailService.selectList(request.getCarId());
            Map<Long, Long> carData = request.getCarData();
            List<Long> upData = new ArrayList<>();
            cartDetailList.stream().forEach(item -> {
                Long id = item.getArticlesId();
                Long num = carData.get(id);
                if (num!=null) {
                    Long invent = item.getQuantity();
                    if (num < 0) {
                        throw new RuntimeException("商品数量不能小于0!");
                    }
                    if (num > invent) {
                        buyVO.setIsUp(true);
                        upData.add(id);
                    }
                }
            });
            buyVO.setUpData(upData);
        } else {
            if (BOOK.getType().equals(articlesCategory)) {
                MallBooksSpecificationVO specificationVO = specificationService.getByKey(specificationId);
                inventory = specificationVO.getInventory();
                if (Long.valueOf(quantity) > inventory) {
                    buyVO.setIsUp(true);
                }
            }
            if (OrderTypeEnum.RIM.getType().equals(articlesCategory)) {
                MallPeripherySpecificationVO specificationVO = peripherySpecificationService.getByKey(specificationId);
                inventory = specificationVO.getInventory();
                if (Long.valueOf(quantity) > inventory) {
                    buyVO.setIsUp(true);
                }
            }
            if (OrderTypeEnum.INTEGRAL.getType().equals(articlesCategory)) {
                AssertUtil.assertNotNull(articlesId,"积分商品下单商品ID不能为空!");
                MallIntegrationDO integrationDO = integrationService.lambdaQuery().eq(MallIntegrationDO::getId, articlesId).one();
                inventory = integrationDO.getSurplusInventory();
                if (Long.valueOf(quantity) > inventory) {
                    buyVO.setIsUp(true);
                }
            }
        }
        return buyVO;
    }

    /**
     * 判断是否包邮->判断是否满足条件包邮->根据客户选择的运送方式判断地区->没有所在地区则使用默认运费->求最大首费和最小续费
     * @param request
     * @return
     */
    @Override
    public MallArticlesBuyVO calculateFreight(MallBuyRequest request) {
        MallArticlesBuyVO articlesBuyVO = new MallArticlesBuyVO();
        FreeDeliverySetVO deliverySetVO = freeDeliverySetService.selectOne();
        if (TRUE.getCode()==deliverySetVO.getTurnSwitch()){
            BigDecimal amount = request.getAmount();
            BigDecimal setVOPrice = deliverySetVO.getPrice();
            if (amount.compareTo(setVOPrice)>=0){
                articlesBuyVO.setIsFree(true);
                articlesBuyVO.setFreePrice(ZERO);
                return articlesBuyVO;
            }
        }
        Long addressId = request.getAddressId();
        AssertUtil.assertNotNull(addressId,"请选择收货地址!");
        //JD物流前置校验
        AddressDO addressDO = addressService.lambdaQuery().eq(AddressDO::getId, addressId).one();
        jdPreCheck(addressDO);
        articlesBuyVO.setIsFree(false);
        Long carId = request.getCarId();
        BigDecimal amount = request.getAmount();
        if (carId==null){//单商品运费计算
            Long freeTemplateId = request.getFreeTemplateId();
            AssertUtil.assertNotNull(freeTemplateId,"运费模板ID不能为空!");
            Integer articlesCategory = request.getArticlesCategory();
            AssertUtil.assertNotNull(articlesCategory,"商品类别不能为空!");
            Long specificationId = request.getSpecificationId();
            AssertUtil.assertNotNull(specificationId,"规格ID不能为空!");
            Integer quantity = request.getQuantity();
            if (BOOK.getType().equals(articlesCategory)){
                calculationBookFree(articlesBuyVO, amount, addressId, freeTemplateId, specificationId, quantity);
            }
            if (RIM.getType().equals(articlesCategory)){
                calculationRimFree(articlesBuyVO, amount, addressId, freeTemplateId, specificationId, quantity);
            }
            if(INTEGRAL.getType().equals(articlesCategory)){
                Long articlesId = request.getArticlesId();
                AssertUtil.assertNotNull(articlesId,"商品ID不能为空!");
                MallIntegrationDO integrationDO = integrationService.lambdaQuery().eq(MallIntegrationDO::getId, articlesId).one();
                Integer category = integrationDO.getArticlesCategory();
                if (BOOK.getType().equals(category)){
                    calculationBookFree(articlesBuyVO, amount, addressId, freeTemplateId, specificationId, quantity);
                }
                if (RIM.getType().equals(category)){
                    calculationRimFree(articlesBuyVO, amount, addressId, freeTemplateId, specificationId, quantity);
                }
            }
        }else {//购物车运费计算
            List<CartSpecificationVO> cartDetailList = cartDetailService.selectCartSpecificationList(request.getCarId());
            //省ID-市ID-区ID
            String str = addressService.selectInfoById(addressId);
            Map<Long, Long> carData = request.getCarData();
            List<BigDecimal> maxFirstFreePriceList = new ArrayList<>();//首费集合
            List<FreeCarryModeInfoVO> pieceCarryModeList = new ArrayList<>();//满足运送条件的运送方式
            List<FreeCarryModeInfoVO> weightCarryModeList = new ArrayList<>();
            List<FreeCarryModeInfoVO> bulkCarryModeList = new ArrayList<>();
            AtomicReference<BigDecimal> totalKg = new AtomicReference<>(new BigDecimal(0));
            AtomicReference<BigDecimal> totalMl = new AtomicReference<>(new BigDecimal(0));
            AtomicInteger totalQuantity = new AtomicInteger(0);
            //寻找最大首费和最小续费
            if (CollectionUtils.isNotEmpty(cartDetailList)) {
                cartDetailList.stream().forEach(item -> {
                    Long num = carData.get(item.getArticlesId());
                    if (num!=null) {//不为空才是购物车选择结算的商品
                        Integer quantity = num.intValue();
                        totalQuantity.set(totalQuantity.get()+quantity);
                        Long freeTemplateId = item.getFreeTemplateId();
                        FreeTemplateInfoVO templateInfoVO = templateService.selectFreeTempInfoByFreeTemplateId(freeTemplateId);
                        Integer freeOrNot = templateInfoVO.getFreeOrNot();
                        Integer valuationModel = templateInfoVO.getValuationModel();
                        if (FreeEnum.PINKAGE.getType().equals(freeOrNot)){
                            checkIsFree(templateInfoVO, quantity, articlesBuyVO, item.getWeight(), item.getVolume(), amount, addressId);
                            if (!articlesBuyVO.getIsFree()){//获取当件商品的首费
                                BigDecimal volume = new BigDecimal(quantity).multiply(item.getVolume());
                                BigDecimal weight =  new BigDecimal(quantity).multiply(item.getWeight());
                                totalKg.set(totalKg.get().add(weight));
                                totalMl.set(totalMl.get().add(volume));
                                List<FreeCarryModeInfoVO> carryModeS = templateInfoVO.getCarryModeS();
                                List<FreeCarryModeInfoVO> collect = carryModeS.stream().filter(mode -> mode.getRegion().contains(str)).collect(Collectors.toList());
                                if (CollectionUtils.isNotEmpty(collect)) {
                                    if (FreeEnum.PIECE.getType().equals(valuationModel)){
                                        pieceCarryModeList.addAll(collect);
                                    }else if (FreeEnum.KG.getType().equals(valuationModel)){
                                        weightCarryModeList.addAll(collect);
                                    }
                                    else if (FreeEnum.ML.getType().equals(valuationModel)){
                                        bulkCarryModeList.addAll(collect);
                                    }
                                    BigDecimal max = collect.stream().map(FreeCarryModeInfoVO::getFirstPrice).max(Comparator.naturalOrder()).orElse(null);
                                    maxFirstFreePriceList.add(max);
                                }else {
                                    List<FreeCarryModeInfoVO> list = carryModeS.stream().filter(mode -> "ALL".equals(mode.getRegion())).collect(Collectors.toList());
                                    if (CollectionUtils.isNotEmpty(list)){
                                        if (FreeEnum.PIECE.getType().equals(valuationModel)){
                                            pieceCarryModeList.addAll(list);
                                        }else if (FreeEnum.KG.getType().equals(valuationModel)){
                                            weightCarryModeList.addAll(list);
                                        }
                                        else if (FreeEnum.ML.getType().equals(valuationModel)){
                                            bulkCarryModeList.addAll(list);
                                        }
                                        BigDecimal max = list.stream().map(FreeCarryModeInfoVO::getFirstPrice).max(Comparator.naturalOrder()).orElse(null);
                                        maxFirstFreePriceList.add(max);
                                    }
                                }
                            }
                        }else {
                            BigDecimal volume = new BigDecimal(quantity).multiply(item.getVolume());
                            BigDecimal weight =  new BigDecimal(quantity).multiply(item.getWeight());
                            totalKg.set(totalKg.get().add(weight));
                            totalMl.set(totalMl.get().add(volume));
                            List<FreeCarryModeInfoVO> carryModeS = templateInfoVO.getCarryModeS();
                            List<FreeCarryModeInfoVO> collect = carryModeS.stream().filter(mode -> mode.getRegion().contains(str)).collect(Collectors.toList());
                            if (CollectionUtils.isNotEmpty(collect)) {
                                if (FreeEnum.PIECE.getType().equals(valuationModel)){
                                    pieceCarryModeList.addAll(collect);
                                }else if (FreeEnum.KG.getType().equals(valuationModel)){
                                    weightCarryModeList.addAll(collect);
                                }
                                else if (FreeEnum.ML.getType().equals(valuationModel)){
                                    bulkCarryModeList.addAll(collect);
                                }
                                BigDecimal max = collect.stream().map(FreeCarryModeInfoVO::getFirstPrice).max(Comparator.naturalOrder()).orElse(null);
                                maxFirstFreePriceList.add(max);
                            }else {
                                List<FreeCarryModeInfoVO> list = carryModeS.stream().filter(mode -> "ALL".equals(mode.getRegion())).collect(Collectors.toList());
                                if (FreeEnum.PIECE.getType().equals(valuationModel)){
                                    pieceCarryModeList.addAll(list);
                                }else if (FreeEnum.KG.getType().equals(valuationModel)){
                                    weightCarryModeList.addAll(list);
                                }
                                else if (FreeEnum.ML.getType().equals(valuationModel)){
                                    bulkCarryModeList.addAll(list);
                                }
                                BigDecimal max = list.stream().map(FreeCarryModeInfoVO::getFirstPrice).max(Comparator.naturalOrder()).orElse(null);
                                maxFirstFreePriceList.add(max);
                            }
                        }
                    }
                });
                BigDecimal maxFirstFree = maxFirstFreePriceList.stream().max(Comparator.naturalOrder()).orElse(ZERO);
                BigDecimal minPieceSecondPrice = null;
                BigDecimal minWeightSecondPrice = null;
                BigDecimal minBulkSecondPrice = null;
                //求最小续费
                if (CollectionUtils.isNotEmpty(pieceCarryModeList)){//按件续费
                    minPieceSecondPrice = pieceCarryModeList.stream().map(item -> {
                        BigDecimal secondPrice = item.getSecondPrice();
                        Long secondPiece = item.getSecondPiece();
                        Integer firstPiece = item.getFirstPiece().intValue();
                        Integer quantity = totalQuantity.get();
                        if (quantity <= firstPiece) {
                            return new BigDecimal(0);
                        } else {
                            return new BigDecimal(quantity - firstPiece).divide(new BigDecimal(secondPiece), 0, RoundingMode.UP).multiply(secondPrice).setScale(2, RoundingMode.HALF_UP);
                        }
                    }).min(Comparator.naturalOrder()).orElse(null);
                }
                if (CollectionUtils.isNotEmpty(weightCarryModeList)){//按重量续费
                    minWeightSecondPrice = weightCarryModeList.stream().map(item -> {
                        BigDecimal secondPrice = item.getSecondPrice();
                        BigDecimal secondWeight = item.getSecondWeight();
                        BigDecimal firstWeight = item.getFirstWeight();
                        BigDecimal totalWeight = totalKg.get();
                        if (firstWeight.compareTo(totalWeight) == 1) {
                            return new BigDecimal(0);
                        } else {
                            return totalWeight.subtract(firstWeight).divide(secondWeight, 0, RoundingMode.UP).multiply(secondPrice).setScale(2, RoundingMode.HALF_UP);
                        }
                    }).min(Comparator.naturalOrder()).orElse(null);
                }
                if (CollectionUtils.isNotEmpty(bulkCarryModeList)){//按体积续费
                    minBulkSecondPrice = bulkCarryModeList.stream().map(item -> {
                        BigDecimal secondPrice = item.getSecondPrice();
                        BigDecimal secondBulk = item.getSecondBulk();
                        BigDecimal firstBulk = item.getFirstBulk();
                        BigDecimal totalBulk = totalMl.get();
                        if (firstBulk.compareTo(totalBulk) == 1) {
                            return new BigDecimal(0);
                        } else {
                            return totalBulk.subtract(firstBulk).divide(secondBulk, 0, RoundingMode.UP).multiply(secondPrice).setScale(2, RoundingMode.HALF_UP);
                        }
                    }).min(Comparator.naturalOrder()).orElse(null);
                }
                BigDecimal minSecondFree = Stream.of(minPieceSecondPrice, minWeightSecondPrice, minBulkSecondPrice)
                        .filter(Objects::nonNull) // 过滤掉为 null 的值
                        .min(Comparator.naturalOrder()) // 使用 Comparator.naturalOrder() 比较三个值，并取最小值
                        .orElse(new BigDecimal(0));
                articlesBuyVO.setFreePrice(maxFirstFree.add(minSecondFree).setScale(2,RoundingMode.HALF_UP));
            }else {
                throw new RuntimeException("购物车商品数量不能为空!");
            }
        }
        return articlesBuyVO;
    }

    private void calculationRimFree(MallArticlesBuyVO articlesBuyVO, BigDecimal amount, Long addressId, Long freeTemplateId, Long specificationId, Integer quantity) {
        MallPeripherySpecificationVO specificationVO = peripherySpecificationService.getByKey(specificationId);
        FreeTemplateInfoVO templateInfoVO = templateService.selectFreeTempInfoByFreeTemplateId(freeTemplateId);
        Integer freeOrNot = templateInfoVO.getFreeOrNot();
        //包邮，查包邮条件是否满足
        if (FreeEnum.PINKAGE.getType().equals(freeOrNot)){
            checkIsFree(templateInfoVO, quantity, articlesBuyVO, specificationVO.getWeight(), specificationVO.getVolume(), amount, addressId);
            if (!articlesBuyVO.getIsFree()) {//不满足包邮条件
                setPeripheryFreePrice(articlesBuyVO, addressId, quantity, specificationVO, templateInfoVO);
            }
        }
        //不包邮，运费计算
        if (FreeEnum.NOT_PINKAGE.getType().equals(freeOrNot)){
            setPeripheryFreePrice(articlesBuyVO, addressId, quantity, specificationVO, templateInfoVO);
        }
    }

    private void calculationBookFree(MallArticlesBuyVO articlesBuyVO, BigDecimal amount, Long addressId, Long freeTemplateId, Long specificationId, Integer quantity) {
        MallBooksSpecificationVO specificationVO = specificationService.getByKey(specificationId);
        FreeTemplateInfoVO templateInfoVO = templateService.selectFreeTempInfoByFreeTemplateId(freeTemplateId);
        Integer freeOrNot = templateInfoVO.getFreeOrNot();
        //包邮，查包邮条件是否满足
        if (FreeEnum.PINKAGE.getType().equals(freeOrNot)){
            checkIsFree(templateInfoVO, quantity, articlesBuyVO, specificationVO.getWeight(), specificationVO.getVolume(), amount, addressId);
            if (!articlesBuyVO.getIsFree()) {//不满足包邮条件
                setBookFreePrice(articlesBuyVO, addressId, quantity, specificationVO, templateInfoVO);
            }
        }
        //不包邮，运费计算
        if (FreeEnum.NOT_PINKAGE.getType().equals(freeOrNot)){
            setBookFreePrice(articlesBuyVO, addressId, quantity, specificationVO, templateInfoVO);
        }
    }

    @Override
    public PageInfo<List<MallOrderListVO>> selectMallOrderList(MallOrderListRequest request, Pageable pageable) {
        PageHelper.startPage(request.getPageNum(), request.getPageSize(), getOrderBy(pageable.getSort())).setReasonable(true);
        List<MallOrderListVO> mallOrderListVOS = mallBooksOrderMapper.selectMallOrderList(request);
        mallOrderListVOS.forEach(item->{
            String orderType = item.getOrderType();
            if (!CART.getType().toString().equals(orderType)){
                MallCarOrderListVO carOrderListVO = new MallCarOrderListVO();
                carOrderListVO.setArticlesId(item.getArticlesId());
                carOrderListVO.setPicture(item.getPicture());
                carOrderListVO.setQuantity(item.getQuantity());
                carOrderListVO.setSpecification(item.getSpecification());
                carOrderListVO.setTitle(item.getTitle());
                carOrderListVO.setIsRefunds(item.getIsRefunds());
                carOrderListVO.setUnitPrice(item.getUnitPrice());
                carOrderListVO.setArticlesCategory(item.getArticlesCategory());
                carOrderListVO.setSpecificationId(item.getSpecificationId());
                List<MallCarOrderListVO> carOrderListVOS = Arrays.asList(carOrderListVO);
                item.setCarOrderList(carOrderListVOS);
            }
        });
        return new PageInfo(mallOrderListVOS);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean cancelOrderWaitPay(MallCancelOrderRequest request) {
        Integer orderType = Integer.valueOf(request.getOrderType());
        Long orderId = request.getOrderId();
        Integer quantity = request.getQuantity();
        AssertUtil.assertNotNull(orderId,"订单ID不能为空!");
        AssertUtil.assertNotNull(orderType,"订单类型不能为空!");
        if (!CART.getType().equals(orderType)){
            AssertUtil.assertNotNull(quantity,"商品数量不能为空!");
        }
        if (BOOK.getType().equals(orderType)){
            Long specificationId = orderDetailsService.selectBookSpecificationId(orderId);
            //删除订单
            mallBooksOrderMapper.deleteDOByIds(Convert.toStrArray(orderId));
            orderDetailsService.deleteBookOrderDetaile(orderId);
            //归还库存
            Map<String, Long> map = new HashMap<>();
            map.put("specificationId", specificationId);
            map.put("quantity",Long.valueOf(quantity));
            specificationService.addQuantity(map);
        }else if (RIM.getType().equals(orderType)){
            Long specificationId = orderDetailsService.selectRimSpecificationId(orderId);
            //删除订单
            periodService.deleteDOByIds(orderId.toString());
            periodsService.deleteRimOrderDetaile(orderId);
            //归还库存
            Map<String, Long> map = new HashMap<>();
            map.put("specificationId", specificationId);
            map.put("quantity",Long.valueOf(quantity));
            peripherySpecificationService.addQuantity(map);
        }else if (INTEGRAL.getType().equals(orderType)){
            MallIntegrationOrderDO integrationOrderDO = integrationOrderService.lambdaQuery().eq(MallIntegrationOrderDO::getId, orderId).one();
            //删除订单
            integrationOrderService.lambdaUpdate().eq(MallIntegrationOrderDO::getId,orderId).remove();

            //归还库存
            MallIntegrationDO integrationDO = integrationService.lambdaQuery()
                    .eq(MallIntegrationDO::getId, integrationOrderDO.getMallIntegrationId())
                    .last("FOR UPDATE")
                    .one();
            integrationService.lambdaUpdate()
                    .set(MallIntegrationDO::getSurplusInventory,integrationDO.getSurplusInventory()+Long.valueOf(quantity))
                    .eq(MallIntegrationDO::getId, integrationDO.getId())
                    .update();
        }else if (CART.getType().equals(orderType)){
            List<MallOrderCarCancelListVO> list = cartOrderDetailsService.selectSpecificationIdByOrderId(orderId);
            list.stream().forEach(item->{
                Integer itemQuantity = item.getQuantity();
                Integer articlesCategory = item.getArticlesCategory();
                Long specificationId = item.getSpecificationId();
                cartOrderService.deleteDOByIds(orderId.toString());
                cartOrderDetailsService.deleteCarOrderDetaile(orderId);
                if (BOOK.getType().equals(articlesCategory)){
                    //归还库存
                    Map<String, Long> map = new HashMap<>();
                    map.put("specificationId", specificationId);
                    map.put("quantity",Long.valueOf(itemQuantity));
                    specificationService.addQuantity(map);
                }
                if (RIM.getType().equals(articlesCategory)){
                    //归还库存
                    Map<String, Long> map = new HashMap<>();
                    map.put("specificationId", specificationId);
                    map.put("quantity",Long.valueOf(itemQuantity));
                    peripherySpecificationService.addQuantity(map);
                }
            });
        }

        return true;
    }

    @Override
    public MallOrderDetailListVO selectOrderDetail(MallCancelOrderRequest request) {
        Long orderId = request.getOrderId();
        Integer orderType = request.getOrderType();
        if (BOOK.getType().equals(orderType)){
            MallOrderDetailListVO mallOrderDetailListVO = orderDetailsService.selectBookOrderDetail(orderId);
            AssertUtil.assertNotNull(mallOrderDetailListVO,"订单不存在!");
            String status = mallOrderDetailListVO.getStatus();
            if (AFTER_SALE.getType().equals(Integer.valueOf(status)) || BEFOR_SALE.getType().equals(Integer.valueOf(status))){
                Integer refundStatus = refundsMapper.selectStatus(orderId);
                mallOrderDetailListVO.setRefundStatus(refundStatus);
            }
            MallCarOrderListVO mallCarOrderListVO = new MallCarOrderListVO();
            mallCarOrderListVO.setArticlesId(mallOrderDetailListVO.getArticlesId());
            mallCarOrderListVO.setPicture(mallOrderDetailListVO.getPicture());
            mallCarOrderListVO.setQuantity(mallOrderDetailListVO.getQuantity());
            mallCarOrderListVO.setSpecification(mallOrderDetailListVO.getSpecification());
            mallCarOrderListVO.setTitle(mallOrderDetailListVO.getTitle());
            mallCarOrderListVO.setIsRefunds(mallOrderDetailListVO.getIsRefunds());
            mallCarOrderListVO.setUnitPrice(mallOrderDetailListVO.getUnitPrice());
            mallCarOrderListVO.setArticlesCategory(BOOK.getType());
            List<MallCarOrderListVO> mallCarOrderListVOS = Arrays.asList(mallCarOrderListVO);
            mallOrderDetailListVO.setCarOrderList(mallCarOrderListVOS);
            return mallOrderDetailListVO;
        }else if (RIM.getType().equals(orderType)){
            MallOrderDetailListVO mallOrderDetailListVO = orderDetailsService.selectRimOrderDetail(orderId);
            AssertUtil.assertNotNull(mallOrderDetailListVO,"订单不存在!");
            String status = mallOrderDetailListVO.getStatus();
            if (AFTER_SALE.getType().equals(Integer.valueOf(status)) || BEFOR_SALE.getType().equals(Integer.valueOf(status))){
                Integer refundStatus = refundsMapper.selectStatus(orderId);
                mallOrderDetailListVO.setRefundStatus(refundStatus);
            }
            MallCarOrderListVO mallCarOrderListVO = new MallCarOrderListVO();
            mallCarOrderListVO.setArticlesId(mallOrderDetailListVO.getArticlesId());
            mallCarOrderListVO.setPicture(mallOrderDetailListVO.getPicture());
            mallCarOrderListVO.setQuantity(mallOrderDetailListVO.getQuantity());
            mallCarOrderListVO.setSpecification(mallOrderDetailListVO.getSpecification());
            mallCarOrderListVO.setTitle(mallOrderDetailListVO.getTitle());
            mallCarOrderListVO.setIsRefunds(mallOrderDetailListVO.getIsRefunds());
            mallCarOrderListVO.setUnitPrice(mallOrderDetailListVO.getUnitPrice());
            mallCarOrderListVO.setArticlesCategory(RIM.getType());
            List<MallCarOrderListVO> mallCarOrderListVOS = Arrays.asList(mallCarOrderListVO);
            mallOrderDetailListVO.setCarOrderList(mallCarOrderListVOS);
            return mallOrderDetailListVO;
        }else if (INTEGRAL.getType().equals(orderType)){
            MallOrderDetailListVO mallOrderDetailListVO = integrationOrderService.selectIntegrationOrderDetail(orderId);
            AssertUtil.assertNotNull(mallOrderDetailListVO,"订单不存在!");
            String status = mallOrderDetailListVO.getStatus();
            if (AFTER_SALE.getType().equals(Integer.valueOf(status)) || BEFOR_SALE.getType().equals(Integer.valueOf(status))){
                Integer refundStatus = refundsMapper.selectStatus(orderId);
                mallOrderDetailListVO.setRefundStatus(refundStatus);
            }
            MallCarOrderListVO mallCarOrderListVO = new MallCarOrderListVO();
            mallCarOrderListVO.setArticlesId(mallOrderDetailListVO.getArticlesId());
            mallCarOrderListVO.setPicture(mallOrderDetailListVO.getPicture());
            mallCarOrderListVO.setQuantity(mallOrderDetailListVO.getQuantity());
            mallCarOrderListVO.setSpecification(mallOrderDetailListVO.getSpecification());
            mallCarOrderListVO.setTitle(mallOrderDetailListVO.getTitle());
            mallCarOrderListVO.setIsRefunds(mallOrderDetailListVO.getIsRefunds());
            mallCarOrderListVO.setUnitPrice(mallOrderDetailListVO.getUnitPrice());
            mallCarOrderListVO.setIntegralPrice(mallOrderDetailListVO.getIntegralPrice());
            mallCarOrderListVO.setPaymentType(mallOrderDetailListVO.getPaymentType());
            mallCarOrderListVO.setArticlesCategory(INTEGRAL.getType());
            List<MallCarOrderListVO> mallCarOrderListVOS = Arrays.asList(mallCarOrderListVO);
            mallOrderDetailListVO.setCarOrderList(mallCarOrderListVOS);
            return mallOrderDetailListVO;
        }else if (CART.getType().equals(orderType)){
            MallOrderDetailListVO mallOrderDetailListVO = cartOrderDetailsService.selectCarOrderDetail(orderId);
            if (mallOrderDetailListVO==null){
                throw new RuntimeException("订单不存在!");
            }
            String status = mallOrderDetailListVO.getStatus();
            if (AFTER_SALE.getType().equals(Integer.valueOf(status)) || BEFOR_SALE.getType().equals(Integer.valueOf(status))){
                Integer refundStatus = refundsMapper.selectStatus(orderId);
                mallOrderDetailListVO.setRefundStatus(refundStatus);
            }
            return mallOrderDetailListVO;
        }
        return new MallOrderDetailListVO();
    }

    @Override
    public WechatRefundsVO selectRefundOrderDetail(MallCancelOrderRequest request) {
        WechatRefundsVO result = refundsMapper.selectRefundOrderDetail(request);
        return result;
    }

    @Override
    public PageInfo<List<AdminMallOrderListVO>> pageList(AdminMallOrderListRequest request, Pageable pageable) {
        PageHelper.startPage(request.getPageNum(), request.getPageSize(), getOrderBy(pageable.getSort())).setReasonable(true);
        List<AdminMallOrderListVO> list = mallBooksOrderMapper.pageList(request);
        return new PageInfo(list);
    }

    @Override
    public WeixinRefundOrderVO cancelOrderIsPay(MallCancelOrderRequest request, WechatRefund wechatRefund) {
        WeixinRefundOrderVO weixinRefundOrderVO = new WeixinRefundOrderVO();
        Integer orderType = Integer.valueOf(request.getOrderType());
        Long orderId = request.getOrderId();
        AssertUtil.assertNotNull(orderType,"订单类型不能为空!");
        AssertUtil.assertNotNull(orderId,"订单ID不能为空!");
        AtomicLong amount = new AtomicLong(0L);
        Long userId = null;
        if (wechatRefund.getOperationType()==0) {
            userId = SessionContext.getWechatUserId();
        }else {
            userId = SessionContext.getAdminUserId();
        }

        String orderNum = "";
        //校验是否发货,已经退款过,是否存在,是否已付款
        if (BOOK.getType().equals(orderType)){
            MallBooksOrderDO booksOrderDO = mallBooksOrderMapper.selectStatusByOrderId(orderId);
            checkOrderRefund(booksOrderDO.getStatus());
            orderNum = booksOrderDO.getOrderNum();
            amount.set(MoneyUtil.yuan2fen(booksOrderDO.getTotalAmount().subtract(booksOrderDO.getFreight()).doubleValue()));
        }else if (RIM.getType().equals(orderType)){
            MallPeripheryOrderDO peripheryOrderDO = peripheryOrderMapper.selectStatusByOrderId(orderId);
            checkOrderRefund(peripheryOrderDO.getStatus());
            orderNum = peripheryOrderDO.getOrderNum();
            amount.set(MoneyUtil.yuan2fen(peripheryOrderDO.getTotalAmount().subtract(peripheryOrderDO.getFreight()).doubleValue()));
        }else if (INTEGRAL.getType().equals(orderType)){
            MallIntegrationOrderDO integrationOrderDO = integrationOrderService.lambdaQuery()
                    .eq(MallIntegrationOrderDO::getId, orderId)
                    .one();
            checkOrderRefund(integrationOrderDO.getStatus());
            Integer paymentType = integrationOrderDO.getPaymentType();
            if (JI_FEN_PAY.getType().equals(paymentType)){//纯积分支付
                //恢复库存
                MallIntegrationDO integrationDO = integrationService.lambdaQuery()
                        .eq(MallIntegrationDO::getId, integrationOrderDO.getMallIntegrationId())
                        .last("FOR UPDATE")
                        .one();
                integrationService.lambdaUpdate()
                        .set(MallIntegrationDO::getSurplusInventory,integrationOrderDO.getQuantity()+integrationDO.getSurplusInventory())
                        .eq(MallIntegrationDO::getId,integrationOrderDO.getMallIntegrationId())
                        .update();
                //退还积分
                PointsAcquireBillRequest billRequest = new PointsAcquireBillRequest();
                billRequest.setUserId(integrationOrderDO.getUserId());
                billRequest.setTitle(INTEGRATION_CANCEL.getType());
                billRequest.setAcquireMode(TUI_KUAN.getType());
                billRequest.setAcquirePoint(integrationOrderDO.getIntegralPrice().intValue());
                pointsService.addPoint(billRequest);
                //修改状态
                integrationOrderService.lambdaUpdate()
                        .set(MallIntegrationOrderDO::getStatus, CANCEL.getType().toString())
                        .set(MallIntegrationOrderDO::getUpdateTime,new Date())
                        .eq(MallIntegrationOrderDO::getId,orderId)
                        .update();
                weixinRefundOrderVO.setOrderId(orderId);
                weixinRefundOrderVO.setOrderType(INTEGRAL.getType());
                weixinRefundOrderVO.setStatus("SUCCESS");
                return weixinRefundOrderVO;
            }
            if (JI_FEN_MONEY_PAY.getType().equals(paymentType)){
                orderNum = integrationOrderDO.getOrderNum();
                amount.set(MoneyUtil.yuan2fen(integrationOrderDO.getPrice().subtract(integrationOrderDO.getFreight()).doubleValue()));
            }
        }else if (CART.getType().equals(orderType)){
            ShoppingCartOrderDO cartOrderDO = cartOrderManager.selectStatusByOrderId(orderId);
            checkOrderRefund(cartOrderDO.getStatus());
            orderNum = cartOrderDO.getOrderNum();
            amount.set(MoneyUtil.yuan2fen(cartOrderDO.getTotalAmount().subtract(cartOrderDO.getFreight()).doubleValue()));
            wechatRefund.setCarData(request.getCarData());
        }
        Integer refundType = request.getRefundType();
        //退款
        String wOrderNum = paymentService.selectWxOrderNumByOrderId(orderId);
        String refundNum = OrderNumUtil.createUniqueOrderNum();
        WeixinJsRefundOrderReq req = new WeixinJsRefundOrderReq();
        req.setTransaction_id(wOrderNum);
        req.setOut_trade_no(orderNum);
        req.setOut_refund_no(refundNum);
        req.setReason("取消订单");
        RefundAmount refundAmount = new RefundAmount();
        if (OrderRefundEnum.ALL_REFUND.getType().equals(refundType)) {//全部退款
//            refundAmount.setRefund(amount.get());
            refundAmount.setRefund(1L);
            wechatRefund.setAmount(amount.get());
        }else if(OrderRefundEnum.PART_REFUND.getType().equals(refundType)){//部分退款
            BigDecimal refundPrice = request.getRefundPrice();
            if (ZERO.equals(refundPrice) || refundPrice == null){
                throw new BusinessException(ErrorCode.PARAM_ERROR, "退款金额有误!");
            }
            long fen = MoneyUtil.yuan2fen(refundPrice.doubleValue());
//            refundAmount.setRefund(fen);
            refundAmount.setRefund(1L);
            wechatRefund.setAmount(fen);
        }else {
            throw new BusinessException(ErrorCode.PARAM_ERROR, "请选择退款方式!");
        }
        req.setAmount(refundAmount);
        refundAmount.setTotal(1L);
        req.setNotify_url(WechatConfigurationConfig.wxUserWechatRefundNotifyUrl);
        try {
            WeixinJsRefundOrderRes refundOrder = weixinJsClient.createRefundOrder(req);
            String status = refundOrder.getStatus();
            weixinRefundOrderVO.setStatus(status);
            weixinRefundOrderVO.setOrderId(orderId);
            weixinRefundOrderVO.setOrderType(orderType);
            if ("SUCCESS".equals(status)||"PROCESSING".equals(status)){
                wechatRefund.setOrderId(orderId);
                wechatRefund.setOrderType(orderType);
                wechatRefund.setOrderNum(request.getOrderNum());
                wechatRefund.setRefundNum(refundNum);
                wechatRefund.setRefundType(refundType);
                wechatRefund.setUserId(userId);
                redisCacheService.hashPushHashMap(ORDER_REFUND.name(),refundNum,wechatRefund,EXPIRE_SECONDS, TimeUnit.SECONDS);
            }else {
                throw new BusinessException(ErrorCode.ERR_REFUND, "微信退款失败!");
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new BusinessException(ErrorCode.ERR_REFUND, "微信退款失败!");
        }
        return weixinRefundOrderVO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deliverGoods(AdminMallLogisticsRequest request) {
        Long orderId = request.getOrderId();
        Integer orderCategory = request.getOrderCategory();
        Integer num = request.getQuantity();
        String name = request.getName();
        AssertUtil.assertNotNull(name,"商品描述不能为空!");
        AssertUtil.assertNotNull(num,"包裹数量不能为空!");
        AssertUtil.assertNotNull(orderId,"订单ID不能为空!");
        AssertUtil.assertNotNull(orderCategory,"订单类别不能为空!");
        Long addressId = null;
        AtomicReference<BigDecimal> weight = new AtomicReference<>(ZERO);
        AtomicReference<BigDecimal> volume = new AtomicReference<>(ZERO);
        //书籍编码表状态修改为已出售
        if (BOOK.getType().equals(orderCategory)){
            List<String> rasCodeList = request.getRasCodeList();
            AssertUtil.assertNotEmpty(rasCodeList,"书籍RAS编码不能为空!");
            List<MallBooksRasDO> list = rasService.lambdaQuery()
                    .eq(MallBooksRasDO::getIsSell, TRUE.getCode())
                    .in(MallBooksRasDO::getRasCode, rasCodeList)
                    .list();
            List<String> collect = list.stream().map(MallBooksRasDO::getRasCode).collect(Collectors.toList());
            AssertUtil.assertFalse(CollectionUtils.isNotEmpty(list),"扫描的书记编码存在已售卖的编码->{"+JSONObject.toJSONString(collect)+"}");
            List<MallBooksOrderDetailsDO> booksOrderDetailsDOS = orderDetailsService.lambdaQuery()
                    .eq(MallBooksOrderDetailsDO::getMallBooksOrderId, orderId)
                    .list();
            Long sum = booksOrderDetailsDOS.stream().mapToLong(MallBooksOrderDetailsDO::getQuantity).sum();
            AssertUtil.assertFalse(rasCodeList.size()!=sum.intValue(),"RAS编码数量与书籍购买数量不一致!");
            List<Long> bookIds = booksOrderDetailsDOS.stream().map(MallBooksOrderDetailsDO::getMallBooksId).collect(Collectors.toList());
            List<Long> specificationIds = booksOrderDetailsDOS.stream().map(MallBooksOrderDetailsDO::getSpecificationId).collect(Collectors.toList());
            List<MallBooksRasDO> booksRasDOS = rasService.lambdaQuery().in(MallBooksRasDO::getRasCode, rasCodeList).list();
            booksRasDOS.forEach(ras->{
                Long mallBooksId = ras.getMallBooksId();
                Long specificationId = ras.getSpecificationId();
                if (!bookIds.contains(mallBooksId)){
                    MallBooksDO one = bookService.lambdaQuery().eq(MallBooksDO::getId, mallBooksId).one();
                    AssertUtil.assertNotNull(one,"扫码书籍中存在非商城书籍!");
                    AssertUtil.assertNull(one,"扫码书籍中的"+one.getTitle()+"非订单包含书籍!");
                }
                if (!specificationIds.contains(specificationId)){
                    MallBooksDO one = bookService.lambdaQuery().eq(MallBooksDO::getId, mallBooksId).one();
                    AssertUtil.assertNotNull(one,"扫码书籍中存在非商城书籍!");
                    AssertUtil.assertNull(one,"扫码书籍中的"+one.getTitle()+"非订单对应规格书籍!");
                }
            });
            MallBooksOrderDO booksOrderDO = this.lambdaQuery().eq(MallBooksOrderDO::getId, orderId).one();
            addressId = booksOrderDO.getAddressId();
            //计算体积，重量
            booksOrderDetailsDOS.forEach(book->{
                Long quantity = book.getQuantity();
                Long specificationId = book.getSpecificationId();
                MallBooksSpecificationDO booksSpecificationDO = specificationService.lambdaQuery().eq(MallBooksSpecificationDO::getId, specificationId).one();
                BigDecimal booksWeight = booksSpecificationDO.getWeight();
                BigDecimal booksVolume = booksSpecificationDO.getVolume();
                weight.set(weight.get().add(booksWeight.multiply(new BigDecimal(quantity)).setScale(2, RoundingMode.HALF_UP)));
                volume.set(volume.get().add(booksVolume.multiply(new BigDecimal(quantity)).setScale(2, RoundingMode.HALF_UP)));
            });
            rasService.lambdaUpdate()
                    .set(MallBooksRasDO::getIsSell,TRUE.getCode())
                    .set(MallBooksRasDO::getUpdateTime,new Date())
                    .in(MallBooksRasDO::getMallBooksId,bookIds)
                    .in(MallBooksRasDO::getRasCode,rasCodeList)
                    .update();
            //修改订单状态
            this.lambdaUpdate()
                    .set(MallBooksOrderDO::getStatus, FREEING.getType().toString())
                    .set(MallBooksOrderDO::getUpdateTime,new Date())
                    .eq(MallBooksOrderDO::getId,orderId)
                    .update();

        }else if (CART.getType().equals(orderCategory)){
            List<ShoppingCartOrderDetailsDO> list = cartOrderDetailsService.lambdaQuery()
                    .eq(ShoppingCartOrderDetailsDO::getShoppingCartOrderId, orderId)
                    .eq(ShoppingCartOrderDetailsDO::getArticlesCategory, BOOK.getType())
                    .list();
            if (CollectionUtils.isNotEmpty(list)){
                List<String> rasCodeList = request.getRasCodeList();
                AssertUtil.assertNotEmpty(rasCodeList,"书籍RAS编码不能为空!");
                List<MallBooksRasDO> rasDOS = rasService.lambdaQuery()
                        .eq(MallBooksRasDO::getIsSell, TRUE.getCode())
                        .in(MallBooksRasDO::getRasCode, rasCodeList)
                        .list();
                List<String> collect = rasDOS.stream().map(MallBooksRasDO::getRasCode).collect(Collectors.toList());
                AssertUtil.assertFalse(CollectionUtils.isNotEmpty(rasDOS),"扫描的书记编码存在已售卖的编码->{"+JSONObject.toJSONString(collect)+"}");
                Long sum = list.stream().mapToLong(ShoppingCartOrderDetailsDO::getQuantity).sum();
                if (rasCodeList.size()!=sum.intValue()){
                    throw new BusinessException(ErrorCode.PARAM_ERROR, "RAS编码数量与书籍购买数量不一致!");
                }
                List<Long> bookIds = list.stream().map(ShoppingCartOrderDetailsDO::getArticlesId).collect(Collectors.toList());
                List<Long> specificationIds = list.stream().map(ShoppingCartOrderDetailsDO::getSpecificationId).collect(Collectors.toList());
                List<MallBooksRasDO> booksRasDOS = rasService.lambdaQuery().in(MallBooksRasDO::getRasCode, rasCodeList).list();
                booksRasDOS.forEach(ras->{
                    Long mallBooksId = ras.getMallBooksId();
                    Long specificationId = ras.getSpecificationId();
                    if (!bookIds.contains(mallBooksId)){
                        MallBooksDO one = bookService.lambdaQuery().eq(MallBooksDO::getId, mallBooksId).one();
                        AssertUtil.assertNotNull(one,"扫码书籍中存在非商城书籍!");
                        AssertUtil.assertNull(one,"扫码书籍中的"+one.getTitle()+"非订单包含书籍!");
                    }
                    if (!specificationIds.contains(specificationId)){
                        MallBooksDO one = bookService.lambdaQuery().eq(MallBooksDO::getId, mallBooksId).one();
                        AssertUtil.assertNotNull(one,"扫码书籍中存在非商城书籍!");
                        AssertUtil.assertNull(one,"扫码书籍中的"+one.getTitle()+"非订单对应规格书籍!");
                    }
                });
                rasService.lambdaUpdate()
                        .set(MallBooksRasDO::getIsSell,TRUE.getCode())
                        .set(MallBooksRasDO::getUpdateTime,new Date())
                        .in(MallBooksRasDO::getMallBooksId,bookIds)
                        .in(MallBooksRasDO::getRasCode,rasCodeList)
                        .update();
            }
            ShoppingCartOrderDO cartOrderDO = cartOrderService.lambdaQuery().eq(ShoppingCartOrderDO::getId, orderId).one();
            addressId = cartOrderDO.getAddressId();
            List<ShoppingCartOrderDetailsDO> cartOrderDetailsDOS = cartOrderDetailsService.lambdaQuery()
                    .eq(ShoppingCartOrderDetailsDO::getShoppingCartOrderId, orderId)
                    .list();
            //计算体积，重量
            cartOrderDetailsDOS.forEach(car->{
                Integer articlesCategory = car.getArticlesCategory();
                Long quantity = car.getQuantity();
                Long specificationId = car.getSpecificationId();
                if (BOOK.getType().equals(articlesCategory)){
                    MallBooksSpecificationDO booksSpecificationDO = specificationService.lambdaQuery().eq(MallBooksSpecificationDO::getId, specificationId).one();
                    BigDecimal booksWeight = booksSpecificationDO.getWeight();
                    BigDecimal booksVolume = booksSpecificationDO.getVolume();
                    weight.set(weight.get().add(booksWeight.multiply(new BigDecimal(quantity)).setScale(2, RoundingMode.HALF_UP)));
                    volume.set(volume.get().add(booksVolume.multiply(new BigDecimal(quantity)).setScale(2, RoundingMode.HALF_UP)));
                }
                if (RIM.getType().equals(articlesCategory)){
                    MallPeripherySpecificationDO peripherySpecificationDO = peripherySpecificationService.lambdaQuery().eq(MallPeripherySpecificationDO::getId, specificationId).one();
                    BigDecimal booksWeight = peripherySpecificationDO.getWeight();
                    BigDecimal booksVolume = peripherySpecificationDO.getVolume();
                    weight.set(weight.get().add(booksWeight.multiply(new BigDecimal(quantity)).setScale(2, RoundingMode.HALF_UP)));
                    volume.set(volume.get().add(booksVolume.multiply(new BigDecimal(quantity)).setScale(2, RoundingMode.HALF_UP)));
                }
            });
            //修改订单状态
            cartOrderService.lambdaUpdate()
                    .set(ShoppingCartOrderDO::getStatus, FREEING.getType().toString())
                    .set(ShoppingCartOrderDO::getUpdateTime,new Date())
                    .eq(ShoppingCartOrderDO::getId,orderId)
                    .update();
        }else if (RIM.getType().equals(orderCategory)){
            MallPeripheryOrderDO peripheryOrderDO = periodService.lambdaQuery().eq(MallPeripheryOrderDO::getId, orderId).one();
            List<MallPeripheryOrderDetailsDO> list = periodsService.lambdaQuery().eq(MallPeripheryOrderDetailsDO::getMallPeripheryOrderId, orderId).list();
            addressId = peripheryOrderDO.getAddressId();
            //计算体积，重量
            list.forEach(rim->{
                Long quantity = rim.getQuantity();
                Long specificationId = rim.getSpecificationId();
                MallPeripherySpecificationDO peripherySpecificationDO = peripherySpecificationService.lambdaQuery().eq(MallPeripherySpecificationDO::getId, specificationId).one();
                BigDecimal booksWeight = peripherySpecificationDO.getWeight();
                BigDecimal booksVolume = peripherySpecificationDO.getVolume();
                weight.set(weight.get().add(booksWeight.multiply(new BigDecimal(quantity)).setScale(2, RoundingMode.HALF_UP)));
                volume.set(volume.get().add(booksVolume.multiply(new BigDecimal(quantity)).setScale(2, RoundingMode.HALF_UP)));
            });
            //修改订单状态
            periodService.lambdaUpdate()
                    .set(MallPeripheryOrderDO::getStatus, FREEING.getType().toString())
                    .set(MallPeripheryOrderDO::getUpdateTime,new Date())
                    .eq(MallPeripheryOrderDO::getId,orderId)
                    .update();
        }else if (INTEGRAL.getType().equals(orderCategory)){
            MallIntegrationOrderDO integrationOrderDO = integrationOrderService.lambdaQuery().eq(MallIntegrationOrderDO::getId, orderId).one();
            addressId = integrationOrderDO.getAddressId();
            MallIntegrationDO integrationDO = integrationService.lambdaQuery().eq(MallIntegrationDO::getId, integrationOrderDO.getMallIntegrationId()).one();
            Long quantity = integrationOrderDO.getQuantity();
            Long specificationId = integrationDO.getSpecificationId();
            Integer articlesCategory = integrationDO.getArticlesCategory();
            //计算体积，重量
            if (BOOK.getType().equals(articlesCategory)){
                List<String> rasCodeList = request.getRasCodeList();
                AssertUtil.assertNotEmpty(rasCodeList,"书籍RAS编码不能为空!");
                if (rasCodeList.size()!=quantity.intValue()){
                    throw new BusinessException(ErrorCode.PARAM_ERROR, "RAS编码数量与书籍购买数量不一致!");
                }
                List<MallBooksRasDO> rasDOS = rasService.lambdaQuery()
                        .eq(MallBooksRasDO::getIsSell, TRUE.getCode())
                        .in(MallBooksRasDO::getRasCode, rasCodeList)
                        .list();
                List<String> collect = rasDOS.stream().map(MallBooksRasDO::getRasCode).collect(Collectors.toList());
                AssertUtil.assertFalse(CollectionUtils.isNotEmpty(rasDOS),"扫描的书记编码存在已售卖的编码->{"+JSONObject.toJSONString(collect)+"}");
                List<MallBooksRasDO> booksRasDOS = rasService.lambdaQuery().in(MallBooksRasDO::getRasCode, rasCodeList).list();
                booksRasDOS.forEach(ras->{
                    Long mallBooksId = ras.getMallBooksId();
                    Long rasSpecificationId = ras.getSpecificationId();
                    if (!mallBooksId.equals(integrationDO.getArticlesId())){
                        MallBooksDO one = bookService.lambdaQuery().eq(MallBooksDO::getId, mallBooksId).one();
                        AssertUtil.assertNotNull(one,"扫码书籍中存在非商城书籍!");
                        AssertUtil.assertNull(one,"扫码书籍中的"+one.getTitle()+"非订单包含书籍!");
                    }
                    if (!specificationId.equals(rasSpecificationId)){
                        MallBooksDO one = bookService.lambdaQuery().eq(MallBooksDO::getId, mallBooksId).one();
                        AssertUtil.assertNotNull(one,"扫码书籍中存在非商城书籍!");
                        AssertUtil.assertNull(one,"扫码书籍中的"+one.getTitle()+"非订单对应规格书籍!");
                    }
                });
                rasService.lambdaUpdate()
                        .set(MallBooksRasDO::getIsSell,TRUE.getCode())
                        .set(MallBooksRasDO::getUpdateTime,new Date())
                        .eq(MallBooksRasDO::getMallBooksId,integrationDO.getArticlesId())
                        .in(MallBooksRasDO::getRasCode,rasCodeList)
                        .update();
                MallBooksSpecificationDO booksSpecificationDO = specificationService.lambdaQuery().eq(MallBooksSpecificationDO::getId, specificationId).one();
                BigDecimal booksWeight = booksSpecificationDO.getWeight();
                BigDecimal booksVolume = booksSpecificationDO.getVolume();
                weight.set(weight.get().add(booksWeight.multiply(new BigDecimal(quantity)).setScale(2, RoundingMode.HALF_UP)));
                volume.set(volume.get().add(booksVolume.multiply(new BigDecimal(quantity)).setScale(2, RoundingMode.HALF_UP)));
            }
            if (RIM.getType().equals(articlesCategory)){
                MallPeripherySpecificationDO peripherySpecificationDO = peripherySpecificationService.lambdaQuery().eq(MallPeripherySpecificationDO::getId, specificationId).one();
                BigDecimal booksWeight = peripherySpecificationDO.getWeight();
                BigDecimal booksVolume = peripherySpecificationDO.getVolume();
                weight.set(weight.get().add(booksWeight.multiply(new BigDecimal(quantity)).setScale(2, RoundingMode.HALF_UP)));
                volume.set(volume.get().add(booksVolume.multiply(new BigDecimal(quantity)).setScale(2, RoundingMode.HALF_UP)));
            }

            //修改订单状态
            integrationOrderService.lambdaUpdate()
                    .set(MallIntegrationOrderDO::getStatus, FREEING.getType().toString())
                    .set(MallIntegrationOrderDO::getUpdateTime,new Date())
                    .eq(MallIntegrationOrderDO::getId,orderId)
                    .update();
        }
        //新增商家物流信息
        String logisticsOrderNum = "SC" + OrderNumUtil.createJdUniqueOrderNum();
        MallLogisticsRequest logisticsRequest = new MallLogisticsRequest();
        logisticsRequest.setOrderId(orderId);
        logisticsRequest.setLogisticsNum(logisticsOrderNum);
        logisticsRequest.setAddressId(addressId);
        logisticsRequest.setOrderType(orderCategory);
        logisticsRequest.setShippingDate(new Date());
        logisticsRequest.setShippingMethod("JD");
        logisticsRequest.setFreeType(FA_HUO_SHIPING.getType());
        //京东物流系统下单
        //JD物流前置校验
        AddressDO addressDO = addressService.lambdaQuery().eq(AddressDO::getId, addressId).one();
        jdPreCheck(addressDO);
        //物流下单
        CommonCreateOrderResponse commonCreateOrderResponse = creatJDOrder(num, name, addressDO, weight, volume, logisticsOrderNum);
        String waybillCode = commonCreateOrderResponse.getWaybillCode();
        String orderCode = commonCreateOrderResponse.getOrderCode();
        logisticsRequest.setCreateTime(new Date());
        logisticsRequest.setCreateUser(SessionContext.getAdminUserId());
        logisticsRequest.setLogisticsOrderId(orderCode);
        logisticsRequest.setWaybillCode(waybillCode);
        logisticsRequest.setFreight(commonCreateOrderResponse.getFreightPre());
        logisticsService.add(logisticsRequest);
        //订阅物流轨迹
        SubscribeTraceRequest traceRequest = new SubscribeTraceRequest();
        String mobile = addressDO.getMobile();
        String lastFourDigits = mobile.substring(mobile.length() - 4);
        traceRequest.setMobile(lastFourDigits);
        traceRequest.setWaybillCode(waybillCode);
        traceRequest.setOrderCode(orderCode);
        traceRequest.setOrderOrigin(1);
        traceRequest.setCustomerCode(jdProperties.getCustomerCode());
        Response<String> subscribeTrace = jdClient.subscribeTrace(traceRequest);
        log.info("JD物流轨迹信息订阅结果,为空则订阅失败->{}",subscribeTrace.getData());
        return true;
    }

    @Override
    public AdminMallOrderDetailVO orderDetail(AdminMallOrderListRequest request) {
        AdminMallOrderDetailVO orderDetailVO = mallBooksOrderMapper.orderDetail(request);
        return orderDetailVO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean confirmGoods(MallOrderConfirmRequest request) {
        //修改订单状态
        Long orderId = request.getOrderId();
        Integer orderType = request.getOrderType();
        BigDecimal price = request.getPrice();
        AssertUtil.assertNotNull(orderId,"订单ID不能为空!");
        AssertUtil.assertNotNull(orderType,"订单类型不能为空!");
        AssertUtil.assertNotNull(price,"订单价格不能为空!");
        Long userId = SessionContext.getWechatUserId();
        AssertUtil.assertNotNull(userId,"用户ID获取失败,请检查登录情况!");
        if (BOOK.getType().equals(orderType)){
            MallBooksOrderDO booksOrderDO = new MallBooksOrderDO();
            booksOrderDO.setId(orderId);
            booksOrderDO.setStatus(OrderStatusEnum.DONE.getType().toString());
            booksOrderDO.setUpdateTime(new Date());
            booksOrderDO.setUpdateUser(userId);
            mallBooksOrderMapper.updateDO(booksOrderDO);
        }else if (RIM.getType().equals(orderType)){
            MallPeripheryOrderDO peripheryOrderDO = new MallPeripheryOrderDO();
            peripheryOrderDO.setId(orderId);
            peripheryOrderDO.setStatus(OrderStatusEnum.DONE.getType().toString());
            peripheryOrderDO.setUpdateTime(new Date());
            peripheryOrderDO.setUpdateUser(userId);
            peripheryOrderMapper.updateDO(peripheryOrderDO);
        }else if (INTEGRAL.getType().equals(orderType)){
            integrationOrderService.lambdaUpdate()
                    .set(MallIntegrationOrderDO::getStatus,OrderStatusEnum.DONE.getType().toString())
                    .set(MallIntegrationOrderDO::getUpdateTime,new Date())
                    .set(MallIntegrationOrderDO::getUpdateUser,userId)
                    .eq(MallIntegrationOrderDO::getId,orderId)
                    .update();
        }else if (CART.getType().equals(orderType)){
            ShoppingCartOrderRequest cartOrderRequest = new ShoppingCartOrderRequest();
            cartOrderRequest.setId(orderId);
            cartOrderRequest.setStatus(OrderStatusEnum.DONE.getType().toString());
            cartOrderRequest.setUpdateTime(new Date());
            cartOrderRequest.setUpdateUser(userId);
            cartOrderService.updateByKey(cartOrderRequest);
        }
        //修改物流签收时间
        logisticsService.lambdaUpdate()
                .set(MallLogisticsDO::getReceiveGoodsTime,new Date())
                .eq(MallLogisticsDO::getOrderId,orderId)
                .eq(MallLogisticsDO::getFreeType,FA_HUO_SHIPING.getType())
                .update();
        //添加积分
        if (!INTEGRAL.getType().equals(orderType)) {
            PointsAcquireBillRequest acquireBillRequest = new PointsAcquireBillRequest();
            acquireBillRequest.setUserId(userId);
            acquireBillRequest.setTitle(PLACE_ORDER_AND_CONSUME.getType());
            acquireBillRequest.setAcquireMode(XIAO_FEI.getType());
            acquireBillRequest.setAcquirePoint(price.setScale(0, RoundingMode.HALF_UP).intValue());
            acquireBillRequest.setCreateUser(userId);
            acquireBillRequest.setCreateTime(new Date());
            pointsService.addPoint(acquireBillRequest);
        }
        return true;
    }

    @Override
    public List<CommonOrderTraceDetail> traceQuery(MallOrderConfirmRequest request) {
        Long orderId = request.getOrderId();
        MallLogisticsDO logisticsDO = logisticsService.lambdaQuery()
                .eq(MallLogisticsDO::getOrderId, orderId)
                .eq(MallLogisticsDO::getFreeType, FA_HUO_SHIPING.getType())
                .last("limit 1")
                .one();
        // 订单追综
        TraceQueryRequest traceQueryRequest = new TraceQueryRequest();
        traceQueryRequest.setWaybillCode(logisticsDO.getWaybillCode());
        traceQueryRequest.setOrderCode(logisticsDO.getLogisticsOrderId());
        traceQueryRequest.setOrderOrigin(1);
        traceQueryRequest.setCustomerCode(jdProperties.getCustomerCode());
        CommonOrderTraceResponse commonOrderTraceResponse = jdClient.traceQuery(traceQueryRequest);
        return commonOrderTraceResponse.getTraceDetails();
    }

    @Override
    public PrintPullDataVO getPullData(AdminMallOrderListRequest request) {
        Long orderId = request.getOrderId();
        AssertUtil.assertNotNull(orderId,"订单ID不能为空!");
        MallLogisticsDO logisticsDO = logisticsService.lambdaQuery()
                .eq(MallLogisticsDO::getOrderId, orderId)
                .eq(MallLogisticsDO::getFreeType, FA_HUO_SHIPING.getType())
                .one();
        AssertUtil.assertNotNull(logisticsDO,"物流订单不存在!");
        String waybillCode = logisticsDO.getWaybillCode();
        PullDataRequest pullDataRequest = new PullDataRequest();
        pullDataRequest.setObjectId(OrderNumUtil.createUniqueOrderNum());
        WayBillInfoRequest wayBillInfoRequest = new WayBillInfoRequest();
        wayBillInfoRequest.setJdWayBillCode(waybillCode);
        List<WayBillInfoRequest> wayBillInfoRequests = Arrays.asList(wayBillInfoRequest);
        pullDataRequest.setWayBillInfos(wayBillInfoRequests);
        List<PrePrintDataInfo> dataInfos = jdClient.pullData(pullDataRequest);
        PrintPullDataVO printPullDataVO = new PrintPullDataVO();
        List<PrintContentsVO> printData = new ArrayList<>();
        dataInfos.forEach(dataInfo->{
            String perPrintData = dataInfo.getPerPrintData();
            PrintContentsVO printContentsVO = new PrintContentsVO(jdProperties.getTempUrl(), perPrintData);
            printData.add(printContentsVO);
        });
        PrintPullDataVO pullDataVO = printPullDataVO.toPrintPullDataVO(OrderNumUtil.createPrintNum(), printData);
        return pullDataVO;
    }

    private void checkOrderRefund(String status) {
        if (WAIT_RECEIVE.getType().equals(status)){
            throw new BusinessException(ErrorCode.REFUND_CHECK, "商品已发货,请走售后流程!");
        } else if(WAIT_PAY.getType().equals(status)){
            throw new BusinessException(ErrorCode.REFUND_CHECK, "该订单未支付!");
        } else if(DONE.getType().equals(status)){
            throw new BusinessException(ErrorCode.REFUND_CHECK, "订单已完成,请走售后流程!");
        } else if(CANCEL.getType().equals(status)){
            throw new BusinessException(ErrorCode.REFUND_CHECK, "订单已退款,请勿重复退款!");
        } else if(AFTER_SALE.getType().equals(status)){
            throw new BusinessException(ErrorCode.REFUND_CHECK, "订单售后中,请勿重复操作!");
        } else if(BEFOR_SALE.getType().equals(status)){
            throw new BusinessException(ErrorCode.REFUND_CHECK, "订单已售后,请勿重复操作!");
        } else if(status == null || StringUtils.isEmpty(status)){
            throw new BusinessException(ErrorCode.REFUND_CHECK, "订单不存在!");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public UserPurchaseRes payment(MallBuyRequest request) {
        log.info("传参->{}",JSONObject.toJSONString(request));
        Long addressId = request.getAddressId();
        if (addressId == null) {
            throw new RuntimeException("请选择收获地址!");
        }
        UserPurchaseRes vipRes = new UserPurchaseRes();
        //是否是vip 0否 1是
        UserVO wechatUserInfo = SessionContext.getWechatUserInfo();
        Boolean isVip = false;
        if (wechatUserInfo.getVip()!=null){
            isVip = wechatUserInfo.getVip() == 1 ? true : false;
        }
        Long integralPrice = request.getIntegralPrice();
        BigDecimal amount = request.getAmount();//商品总价
        AssertUtil.assertNotNull(amount,"商品价格不能为空!");
        BigDecimal freight = request.getFreight() == null ? new BigDecimal(0) : request.getFreight(); //运费
        BigDecimal totalAmount = ZERO.equals(freight) ? amount : amount.add(freight); //总价
        Long userId = wechatUserInfo.getId();
//        Long userId = 1400974426464258L;
        Long carId = request.getCarId();
        OrderTypeEnum orderTypeEnum = null;
        Long orderId = null;
        String orderNum = "";
        List<Long> orderCarProductIds = new ArrayList<>();
        Long id = request.getOrderId();
        if (id!=null){
            Integer orderType = request.getOrderType();
            AssertUtil.assertNotNull(orderType,"订单类型不能为空!");
            orderId = id;
            orderTypeEnum = OrderTypeEnum.getByType(request.getOrderType());
            orderCarProductIds = request.getCarArticlesIds();
            if (BOOK.getType().equals(orderType)) {
                MallBooksOrderDO booksOrderDO = this.lambdaQuery().eq(MallBooksOrderDO::getId, id).one();
                AssertUtil.assertNotNull(booksOrderDO, "订单不存在");
                BigDecimal bookAmount = booksOrderDO.getTotalAmount();
                AssertUtil.assertTrue(NumberUtil.equals(totalAmount, bookAmount.add(freight)), "支付金额和售卖金额不等");
                orderNum = "SC"+OrderNumUtil.createUniqueOrderNum();
                this.lambdaUpdate().set(MallBooksOrderDO::getOrderNum,orderNum).eq(MallBooksOrderDO::getId, id).update();
            }
            if (OrderTypeEnum.RIM.getType().equals(orderType)) {
                MallPeripheryOrderDO peripheryOrderDO = periodService.lambdaQuery().eq(MallPeripheryOrderDO::getId, id).one();
                AssertUtil.assertNotNull(peripheryOrderDO, "订单不存在");
                BigDecimal bookAmount = peripheryOrderDO.getTotalAmount();
                AssertUtil.assertTrue(NumberUtil.equals(totalAmount, bookAmount.add(freight)), "支付金额和售卖金额不等");
                orderNum = "SC"+OrderNumUtil.createUniqueOrderNum();
                periodService.lambdaUpdate().set(MallPeripheryOrderDO::getOrderNum,orderNum).eq(MallPeripheryOrderDO::getId, id).update();
            }
            if (OrderTypeEnum.INTEGRAL.getType().equals(orderType)) {
                MallIntegrationOrderDO integrationOrderDO = integrationOrderService.lambdaQuery().eq(MallIntegrationOrderDO::getId, id).one();
                AssertUtil.assertNotNull(integrationOrderDO, "订单不存在");
                Long integralPrice1 = integrationOrderDO.getIntegralPrice();
                //查询积分是否足够
                PointsVO pointsVO = pointsService.selectPointInfo(userId);
                Long availablePoints = pointsVO.getAvailablePoints();
                if (availablePoints.intValue() < integralPrice1.intValue()){
                    throw new BusinessException(ErrorCode.PARAM_ERROR, "积分不足!");
                }
                BigDecimal price = integrationOrderDO.getPrice();
                BigDecimal freight1 = integrationOrderDO.getFreight();
                AssertUtil.assertTrue(NumberUtil.equals(totalAmount, price.add(freight1)), "支付金额和售卖金额不等");
                orderNum = "SC"+OrderNumUtil.createUniqueOrderNum();
                integrationOrderService.lambdaUpdate().set(MallIntegrationOrderDO::getOrderNum,orderNum).eq(MallIntegrationOrderDO::getId, id).update();
            }
            if (OrderTypeEnum.CART.getType().equals(orderType)) {
                ShoppingCartOrderDO cartOrderDO = cartOrderService.lambdaQuery().eq(ShoppingCartOrderDO::getId, id).one();
                AssertUtil.assertNotNull(cartOrderDO, "订单不存在");
                BigDecimal cartOrderDOTotalAmount = cartOrderDO.getTotalAmount();
                AssertUtil.assertTrue(NumberUtil.equals(totalAmount, cartOrderDOTotalAmount.add(freight)), "支付金额和售卖金额不等");
                orderNum = "SC"+OrderNumUtil.createUniqueOrderNum();
                cartOrderService.lambdaUpdate().set(ShoppingCartOrderDO::getOrderNum,orderNum).eq(ShoppingCartOrderDO::getId, id).update();
            }
        } else {
            if (carId == null) {
                // 书籍，文创周边下单
                Integer articlesCategory = request.getArticlesCategory();
                AssertUtil.assertNotNull(articlesCategory,"商品类别不能为空!");
                Long specificationId = request.getSpecificationId();
                AssertUtil.assertNotNull(specificationId,"规格ID不能为空!");
                Integer quantity = request.getQuantity();
                AssertUtil.assertNotNull(quantity,"商品数量不能为空!");
                Long inventory;//库存
                if (BOOK.getType().equals(articlesCategory)) {
                    if (ZERO.equals(totalAmount)) {
                        throw new BusinessException(ErrorCode.PARAM_ERROR, "支付金额不能为0!");
                    }
                    MallBooksSpecificationVO specificationVO = specificationService.getByKey(specificationId);
                    String specification = specificationVO.getSpecification();
                    inventory = specificationVO.getInventory();
                    if (Long.valueOf(quantity) > inventory) {
                        throw new RuntimeException("已超出库存");
                    }
                    //减库存
                    Map<String, Long> quantityMap = new HashMap<>();
                    quantityMap.put("quantity", Long.valueOf(quantity));
                    quantityMap.put("specificationId", specificationId);
                    specificationService.updateQuantity(quantityMap);
                    //创建订单
                    MallBooksOrderDO booksOrderDO = buildMallBooksOrderRequest(userId, freight, totalAmount, specification, vipRes);
                    booksOrderDO.setAddressId(addressId);
                    booksOrderDO.setId(getId());
                    mallBooksOrderMapper.insertDO(booksOrderDO);
                    orderNum = booksOrderDO.getOrderNum();
                    //创建订单详情
                    MallBooksOrderDetailsRequest orderDetailsRequest = buildMallBooksOrderDetailsRequest(request, isVip, quantity, specificationVO, booksOrderDO.getId());
                    orderDetailsRequest.setId(getId());
                    orderDetailsService.add(orderDetailsRequest);
                    orderId = booksOrderDO.getId();
                    orderTypeEnum = BOOK;
                    vipRes.setOrderId(orderId);
                    vipRes.setOrderType(BOOK.getType());
                }
                if (OrderTypeEnum.RIM.getType().equals(articlesCategory)) {
                    if (ZERO.equals(totalAmount)) {
                        throw new BusinessException(ErrorCode.PARAM_ERROR, "支付金额不能为0!");
                    }
                    MallPeripherySpecificationVO peripheryVO = peripherySpecificationService.getByKey(specificationId);
                    String specification = peripheryVO.getSpecification();
                    inventory = peripheryVO.getInventory();
                    if (Long.valueOf(quantity) > inventory) {
                        throw new BusinessException(ErrorCode.PARAM_ERROR, "已超出库存");
                    }

                    Map<String, Long> quantityMap = new HashMap<>();
                    quantityMap.put("quantity", Long.valueOf(quantity));
                    quantityMap.put("specificationId", specificationId);
                    peripherySpecificationService.updateQuantity(quantityMap);
                    //创建订单
                    MallPeripheryOrderRequest peripheryOrderRequest = buildMallPeripheryOrderRequest(userId, freight, totalAmount, specification, vipRes);
                    peripheryOrderRequest.setAddressId(addressId);
                    peripheryOrderRequest.setId(getId());
                    periodService.insertDO(peripheryOrderRequest);
                    orderNum = peripheryOrderRequest.getOrderNum();
                    orderId = peripheryOrderRequest.getId();
                    vipRes.setOrderId(orderId);
                    vipRes.setOrderType(RIM.getType());
                    orderTypeEnum = RIM;
                    //创建订单详情
                    MallPeripheryOrderDetailsRequest orderDetailsRequest = buildMallPeripheryOrderDetailsRequest(request, isVip, quantity, peripheryVO, orderId);
                    periodsService.add(orderDetailsRequest);
                }
                if (OrderTypeEnum.INTEGRAL.getType().equals(articlesCategory)) {
                    Long articlesId = request.getArticlesId();
                    Integer paymentType = request.getPaymentType();
                    AssertUtil.assertNotNull(articlesId,"积分商品下单商品ID不能为空!");
                    AssertUtil.assertNotNull(paymentType,"积分商品下单支付类型不能为空!");
                    AssertUtil.assertNotNull(integralPrice,"积分商品下单积分价格不能为空!");
                    MallIntegrationDO integrationDO = integrationService.lambdaQuery().eq(MallIntegrationDO::getId, articlesId).last("FOR UPDATE").one();
                    inventory = integrationDO.getSurplusInventory();
                    if (Long.valueOf(quantity) > inventory) {
                        throw new BusinessException(ErrorCode.PARAM_ERROR, "已超出库存");
                    }
                    //扣库存
                    integrationService.lambdaUpdate().set(MallIntegrationDO::getSurplusInventory,inventory-quantity).eq(MallIntegrationDO::getId, articlesId).update();
                    orderNum = "SC"+OrderNumUtil.createUniqueOrderNum();
                    MallIntegrationOrderRequest mallIntegrationOrderRequest = new MallIntegrationOrderRequest();
                    mallIntegrationOrderRequest.setUserId(userId);
                    mallIntegrationOrderRequest.setAddressId(addressId);
                    mallIntegrationOrderRequest.setMallIntegrationId(articlesId);
                    mallIntegrationOrderRequest.setStatus(WAIT_PAY.getType().toString());
                    mallIntegrationOrderRequest.setOrderNum(orderNum);
                    mallIntegrationOrderRequest.setPaymentType(paymentType);
                    mallIntegrationOrderRequest.setIntegralPrice(integralPrice);
                    mallIntegrationOrderRequest.setFreight(freight);
                    mallIntegrationOrderRequest.setPrice(amount);
                    mallIntegrationOrderRequest.setQuantity(quantity.longValue());
                    mallIntegrationOrderRequest.setIsRefunds(0);
                    // 获取当前时间
                    LocalDateTime currentTime = LocalDateTime.now();
                    // 将当前时间加上30分钟
                    LocalDateTime resultDateTime = currentTime.plusMinutes(30);
                    // 将LocalDateTime转换为Date类型
                    Date timeout = Date.from(resultDateTime.atZone(ZoneId.systemDefault()).toInstant());
                    mallIntegrationOrderRequest.setTimeout(timeout);
                    vipRes.setTimeout(timeout);
                    MallIntegrationOrderDO integrationOrderDO = MallIntegrationOrderDtoMapper.INSTANCE.request2DO(mallIntegrationOrderRequest);
                    integrationOrderDO.setId(getId());
                    mallIntegrationOrderMapper.insertDO(integrationOrderDO);
                    orderId = integrationOrderDO.getId();
                    if (JI_FEN_PAY.getType().equals(paymentType)){//纯积分支付
                        //查询积分是否足够
                        PointsVO pointsVO = pointsService.selectPointInfo(userId);
                        Long availablePoints = pointsVO.getAvailablePoints();
                        if (availablePoints.intValue() < integralPrice.intValue()){
                            throw new BusinessException(ErrorCode.PARAM_ERROR, "积分不足!");
                        }
                        //扣除积分
                        PointsUseBillRequest billRequest = new PointsUseBillRequest();
                        billRequest.setUserId(userId);
                        billRequest.setTitle(POINTS_EXCHANGE.getType());
                        billRequest.setConsumeMode(POINT_XIAO_FEI.getType());
                        billRequest.setConsumePonts(integralPrice.intValue());
                        pointsService.consumPoint(billRequest);
                        //修改订单状态
                        integrationOrderService.lambdaUpdate()
                                .set(MallIntegrationOrderDO::getStatus,WAIT_FREE.getType().toString())
                                .set(MallIntegrationOrderDO::getCreateTime,new Date())
                                .eq(MallIntegrationOrderDO::getId,orderId)
                                .update();
                        vipRes.setIntegrationPayStatus(true);
                        vipRes.setOrderId(orderId);
                        vipRes.setOrderType(INTEGRAL.getType());
                        return vipRes;
                    }
                    if (JI_FEN_MONEY_PAY.getType().equals(paymentType)){//积分+钱支付
                        if (ZERO.equals(totalAmount)) {
                            throw new BusinessException(ErrorCode.PARAM_ERROR, "支付金额不能为0!");
                        }
                        vipRes.setOrderId(orderId);
                        vipRes.setOrderType(INTEGRAL.getType());
                        orderTypeEnum = INTEGRAL;
                    }
                }
            } else {
                // 购物车下单
                Map<Long, Long> carData = request.getCarData();
                if (org.springframework.util.CollectionUtils.isEmpty(carData)) {
                    throw new BusinessException(ErrorCode.PARAM_ERROR, "请选择要结算的商品!");
                }
                List<ShoppingCartDetailVO> cartDetailVOS = cartDetailService.selectList(carId);
                List<ShoppingCartOrderDetailsDO> carOdersList = new ArrayList<>();
                Boolean finalIsVip = isVip;
                List<Long> finalOrderCarProductIds = orderCarProductIds;
                cartDetailVOS.stream().forEach(item -> {
                    Long articlesId = item.getArticlesId();
                    Long quantity = carData.get(articlesId);
                    if (quantity != null) {
                        Integer articlesCategory = item.getArticlesCategory();
                        Integer inventory = item.getInventory();
                        String specification = item.getSpecification();
                        if (Long.valueOf(quantity) > inventory) {
                            throw new BusinessException(ErrorCode.PARAM_ERROR, "已超出库存");
                        }
                        ShoppingCartOrderDetailsDO orderDetailsDO = new ShoppingCartOrderDetailsDO();
                        orderDetailsDO.setArticlesId(item.getArticlesId());
                        orderDetailsDO.setQuantity(quantity);
                        orderDetailsDO.setRecordOrNot(0);
                        orderDetailsDO.setIsRefunds(0);
                        orderDetailsDO.setSpecification(specification);
                        orderDetailsDO.setSpecificationId(item.getSpecificationId());
                        Map<String, Long> quantityMap = new HashMap<>();
                        quantityMap.put("quantity", Long.valueOf(quantity));
                        quantityMap.put("specificationId", item.getSpecificationId());
                        if (finalIsVip) {
                            orderDetailsDO.setUnitPrice(item.getVipPrice());
                        } else {
                            orderDetailsDO.setUnitPrice(item.getPrice());
                        }
                        if (BOOK.getType().equals(articlesCategory)) {
                            orderDetailsDO.setArticlesCategory(1);
                            //减库存
                            specificationService.updateQuantity(quantityMap);
                        }
                        if (OrderTypeEnum.RIM.getType().equals(articlesCategory)) {
                            orderDetailsDO.setArticlesCategory(2);
                            //减库存
                            peripherySpecificationService.updateQuantity(quantityMap);
                        }
                        finalOrderCarProductIds.add(articlesId);
                        carOdersList.add(orderDetailsDO);
                    }
                });

                if (CollectionUtils.isEmpty(orderCarProductIds)) {
                    throw new BusinessException(ErrorCode.PARAM_ERROR, "结算数据为空!");
                }
                //修改购物车商品结算状态
                cartDetailService.updateByParam(carId, orderCarProductIds);

                //创建购物车订单
                ShoppingCartOrderRequest shoppingCartOrderRequest = new ShoppingCartOrderRequest();
                // 获取当前时间
                LocalDateTime currentTime = LocalDateTime.now();
                // 将当前时间加上30分钟
                LocalDateTime resultDateTime = currentTime.plusMinutes(30);
                Date timeout = Date.from(resultDateTime.atZone(ZoneId.systemDefault()).toInstant());
                shoppingCartOrderRequest.setTimeout(timeout);
                orderNum = "SC"+OrderNumUtil.createUniqueOrderNum();
                shoppingCartOrderRequest.setUserId(userId);
                shoppingCartOrderRequest.setStatus(WAIT_PAY.getType().toString());
                shoppingCartOrderRequest.setOrderNum(orderNum);
                shoppingCartOrderRequest.setTotalAmount(totalAmount);
                shoppingCartOrderRequest.setShoppingCartId(carId);
                shoppingCartOrderRequest.setFreight(freight);
                shoppingCartOrderRequest.setAddressId(addressId);
                shoppingCartOrderRequest.setId(getId());
                orderId = shoppingCartOrderRequest.getId();
                cartOrderService.insertDO(shoppingCartOrderRequest);
                vipRes.setOrderId(orderId);
                vipRes.setOrderType(4);
                orderTypeEnum = CART;
                Long finalOrderId = orderId;
                carOdersList.forEach(item -> {
                    item.setId(getId());
                    item.setShoppingCartOrderId(finalOrderId);
                });
                cartOrderDetailsService.batchInsert(carOdersList);
                vipRes.setTimeout(timeout);
            }
        }
        redisCacheService.hashPushHashMap(CAR_ORDER_PRODUCT_IDS.name(),orderId.toString(),orderCarProductIds, EXPIRE_SECONDS, TimeUnit.SECONDS);
        //创建微信预订单
        WechatPay wechatPay = new WechatPay();
        wechatPay.setUserId(userId);
        wechatPay.setOrderId(orderId.toString());
        wechatPay.setOrderType(orderTypeEnum.getType());
        wechatPay.setAmount(totalAmount.toPlainString());
        wechatPay.setIntegralPrice(integralPrice);
        String attach = JSONObject.toJSONString(wechatPay);
        WeixinJsCreateOrderReq req = new WeixinJsCreateOrderReq(orderNum, totalAmount.doubleValue(), attach, request.getOpenId());
        try {
            WeixinJsCreateOrderRes res = weixinJsClient.createOrder(req);
            buildPayRes(vipRes, res.getPrepay_id());
        } catch (Exception e) {
            log.error("微信下单失败->{}", e.getMessage());
            throw new BusinessException(ErrorCode.PARAM_ERROR, "微信下单失败!");
        }
        return vipRes;
    }

    @Override
    public List<Map<String, Long>> selectQuantity(WechatPay wechatPay) {
        Integer type = wechatPay.getOrderType();
        Long orderId = Long.valueOf(wechatPay.getOrderId());
        if (CART.getType().equals(type)){//购物车
            return cartOrderDetailsService.selectQuantity(orderId,wechatPay.getCarOrderIds());
        }
        if (SCHOOLBAG.getType().equals(type)){//书包

        }
        List<Map<String, Long>> list = new ArrayList<>();
        list.add(orderDetailsService.selectQuantity(orderId,type));
        return list;
    }

    /**
     * 组装下单支付参数
     *
     * @param res
     * @param prepayId
     * @throws UnsupportedEncodingException
     * @throws NoSuchAlgorithmException
     * @throws SignatureException
     * @throws InvalidKeyException
     */
    private void buildPayRes(UserPurchaseRes res, String prepayId) throws UnsupportedEncodingException, NoSuchAlgorithmException, SignatureException, InvalidKeyException {
        res.setAppId(WechatConfigurationConfig.wxUserWechatAppid);
        res.setTimeStamp(System.currentTimeMillis() / 1000 + "");
        res.setNonceStr(UUID.randomUUID().toString().replaceAll("-", "").toUpperCase());
        res.setSignType("RSA");
        res.setDetailExtend("prepay_id=" + prepayId);
        // 签名，使用字段appId、timeStamp、nonceStr、package计算得出的签名值
        String preSign = res.getAppId() + "\n" + res.getTimeStamp() + "\n" + res.getNonceStr() + "\n" + res.getDetailExtend() + "\n";
        PrivateKey privateKey = PemUtil.loadPrivateKey(new ByteArrayInputStream(WechatConfigurationConfig.wxUserWechatPayApiClientKey.getBytes("utf-8")));
        String paySign = WeixinUtil.sign(preSign.getBytes(StandardCharsets.UTF_8), privateKey);
        res.setPaySign(paySign);
    }

    @NotNull
    private MallBooksOrderDO buildMallBooksOrderRequest(Long userId, BigDecimal freight, BigDecimal totalAmount, String specification,UserPurchaseRes vipRes) {
        MallBooksOrderDO booksOrderDO = new MallBooksOrderDO();
        String orderNum = "SC"+OrderNumUtil.createUniqueOrderNum();
        booksOrderDO.setUserId(userId);
        booksOrderDO.setStatus(WAIT_PAY.getType().toString());
        booksOrderDO.setOrderNum(orderNum);
        booksOrderDO.setTotalAmount(totalAmount);
        booksOrderDO.setFreight(freight);
        booksOrderDO.setSpecification(specification);
        // 获取当前时间
        LocalDateTime currentTime = LocalDateTime.now();
        // 将当前时间加上30分钟
        LocalDateTime resultDateTime = currentTime.plusMinutes(30);
        // 将LocalDateTime转换为Date类型
        Date timeout = Date.from(resultDateTime.atZone(ZoneId.systemDefault()).toInstant());
        booksOrderDO.setTimeout(timeout);
        vipRes.setTimeout(timeout);
        return booksOrderDO;
    }

    @NotNull
    private MallBooksOrderDetailsRequest buildMallBooksOrderDetailsRequest(MallBuyRequest request, Boolean isVip, Integer quantity, MallBooksSpecificationVO specificationVO, Long orderId) {
        MallBooksOrderDetailsRequest orderDetailsRequest = new MallBooksOrderDetailsRequest();
        orderDetailsRequest.setMallBooksOrderId(orderId);
        Long articlesId = request.getArticlesId();
        AssertUtil.assertNotNull(articlesId,"商品ID不能为空");
        orderDetailsRequest.setMallBooksId(articlesId);
        orderDetailsRequest.setQuantity(Long.valueOf(quantity));
        orderDetailsRequest.setSpecificationId(specificationVO.getId());
        if (isVip) {
            orderDetailsRequest.setUnitPrice(specificationVO.getVipPrice());
        } else {
            orderDetailsRequest.setUnitPrice(specificationVO.getPrice());
        }
        orderDetailsRequest.setRecordOrNot(0);
        orderDetailsRequest.setIsRefunds(0);
        return orderDetailsRequest;
    }

    @NotNull
    private MallPeripheryOrderRequest buildMallPeripheryOrderRequest(Long userId, BigDecimal freight, BigDecimal totalAmount, String specification,UserPurchaseRes vipRes) {
        MallPeripheryOrderRequest peripheryOrderRequest = new MallPeripheryOrderRequest();
        String orderNum = "SC"+OrderNumUtil.createUniqueOrderNum();
        peripheryOrderRequest.setUserId(userId);
        peripheryOrderRequest.setStatus(WAIT_PAY.getType().toString());
        peripheryOrderRequest.setOrderNum(orderNum);
        peripheryOrderRequest.setTotalAmount(totalAmount);
        peripheryOrderRequest.setFreight(freight);
        peripheryOrderRequest.setSpecification(specification);
        // 获取当前时间
        LocalDateTime currentTime = LocalDateTime.now();
        // 将当前时间加上30分钟
        LocalDateTime resultDateTime = currentTime.plusMinutes(30);
        // 将LocalDateTime转换为Date类型
        Date timeout = Date.from(resultDateTime.atZone(ZoneId.systemDefault()).toInstant());
        peripheryOrderRequest.setTimeout(timeout);
        vipRes.setTimeout(timeout);
        return peripheryOrderRequest;
    }

    @NotNull
    private MallPeripheryOrderDetailsRequest buildMallPeripheryOrderDetailsRequest(MallBuyRequest request, Boolean isVip, Integer quantity, MallPeripherySpecificationVO peripheryVO, Long orderId) {
        MallPeripheryOrderDetailsRequest orderDetailsRequest = new MallPeripheryOrderDetailsRequest();
        orderDetailsRequest.setMallPeripheryOrderId(orderId);
        orderDetailsRequest.setMallPeripheryId(request.getArticlesId());
        orderDetailsRequest.setQuantity(Long.valueOf(quantity));
        orderDetailsRequest.setSpecificationId(peripheryVO.getId());
        if (isVip) {
            orderDetailsRequest.setUnitPrice(peripheryVO.getVipPrice());
        } else {
            orderDetailsRequest.setUnitPrice(peripheryVO.getPrice());
        }
        orderDetailsRequest.setIsRefunds(0);
        return orderDetailsRequest;
    }

    /**
     * 按照运费类型计算邮费(书籍)
     * @param quantity 购买数量
     * @param specificationVO 规格信息
     * @param carryModeInfoVO 运费模板信息
     * @param valuationModel 运输类型(件、重量、体积)
     */
    private BigDecimal getBookFreePrice(Integer quantity, MallBooksSpecificationVO specificationVO, FreeCarryModeInfoVO carryModeInfoVO, Integer valuationModel) {
        //首费
        BigDecimal firstPrice = carryModeInfoVO.getFirstPrice();
        //续费
        BigDecimal secondPrice = carryModeInfoVO.getSecondPrice();
        if (FreeEnum.PIECE.getType().equals(valuationModel)){
            Integer firstPiece = carryModeInfoVO.getFirstPiece().intValue();
            if (firstPiece>= quantity){
                return firstPrice;
            }else {
                Integer piece = quantity - firstPiece;
                Integer secondPiece = carryModeInfoVO.getSecondPiece().intValue();
                BigDecimal scale = new BigDecimal(piece).divide(new BigDecimal(secondPiece), 0, RoundingMode.UP).multiply(secondPrice).add(firstPrice).setScale(2, RoundingMode.HALF_UP);
                return scale;
            }
        }
        if (FreeEnum.KG.getType().equals(valuationModel)){
            BigDecimal firstWeight = carryModeInfoVO.getFirstWeight();
            BigDecimal weight = specificationVO.getWeight().multiply(new BigDecimal(quantity));
            if (weight.compareTo(firstWeight) == -1){
                return firstPrice;
            }else {
                BigDecimal secondWeight = carryModeInfoVO.getSecondWeight();
                BigDecimal scale = weight.subtract(firstWeight).divide(secondWeight, 0, RoundingMode.UP).multiply(secondPrice).add(firstPrice).setScale(2, RoundingMode.HALF_UP);
                return scale;
            }
        }
        if (FreeEnum.ML.getType().equals(valuationModel)){
            BigDecimal firstBulk = carryModeInfoVO.getFirstBulk();
            BigDecimal volume = specificationVO.getVolume().multiply(new BigDecimal(quantity));
            if (volume.compareTo(firstBulk) == -1){
                return firstPrice;
            }else {
                BigDecimal secondBulk = carryModeInfoVO.getSecondBulk();
                BigDecimal scale = volume.subtract(firstBulk).divide(secondBulk, 0, RoundingMode.UP).multiply(secondPrice).add(firstPrice).setScale(2, RoundingMode.HALF_UP);
                return scale;
            }
        }
        return null;
    }

    /**
     * 按照运费类型计算邮费(周边)
     * @param quantity 购买数量
     * @param specificationVO 规格信息
     * @param carryModeInfoVO 运费模板信息
     * @param valuationModel 运输类型(件、重量、体积)
     */
    private BigDecimal getPeripheryFreePrice(Integer quantity, MallPeripherySpecificationVO specificationVO, FreeCarryModeInfoVO carryModeInfoVO, Integer valuationModel) {
        //首费
        BigDecimal firstPrice = carryModeInfoVO.getFirstPrice();
        //续费
        BigDecimal secondPrice = carryModeInfoVO.getSecondPrice();
        if (FreeEnum.PIECE.getType().equals(valuationModel)){
            Integer firstPiece = carryModeInfoVO.getFirstPiece().intValue();
            if (firstPiece>= quantity){
                return firstPrice;
            }else {
                Integer piece = quantity - firstPiece;
                Integer secondPiece = carryModeInfoVO.getSecondPiece().intValue();
                BigDecimal scale = new BigDecimal(piece).divide(new BigDecimal(secondPiece), 0, RoundingMode.UP).multiply(secondPrice).add(firstPrice).setScale(2, RoundingMode.HALF_UP);
                return scale;
            }
        }
        if (FreeEnum.KG.getType().equals(valuationModel)){
            BigDecimal firstWeight = carryModeInfoVO.getFirstWeight();
            BigDecimal weight = specificationVO.getWeight().multiply(new BigDecimal(quantity));
            if (weight.compareTo(firstWeight) == -1){
                return firstPrice;
            }else {
                BigDecimal secondWeight = carryModeInfoVO.getSecondWeight();
                BigDecimal scale = weight.subtract(firstWeight).divide(secondWeight, 0, RoundingMode.UP).multiply(secondPrice).add(firstPrice).setScale(2, RoundingMode.HALF_UP);
                return scale;
            }
        }
        if (FreeEnum.ML.getType().equals(valuationModel)){
            BigDecimal firstBulk = carryModeInfoVO.getFirstBulk();
            BigDecimal volume = specificationVO.getVolume().multiply(new BigDecimal(quantity));
            if (volume.compareTo(firstBulk) == -1){
                return firstPrice;
            }else {
                BigDecimal secondBulk = carryModeInfoVO.getSecondBulk();
                BigDecimal scale = volume.subtract(firstBulk).divide(secondBulk, 0, RoundingMode.UP).multiply(secondPrice).add(firstPrice).setScale(2, RoundingMode.HALF_UP);
                return scale;
            }
        }
        return null;
    }

    /**
     * 检查书籍是否满足包邮条件
     * @param quantity
     * @param amount
     * @param specificationVO
     * @param termsInfoVO
     */
    private Boolean checkBookFree(Integer quantity, BigDecimal amount, MallBooksSpecificationVO specificationVO, FreeDeliveryTermsInfoVO termsInfoVO) {
        Long pieceNo = termsInfoVO.getPieceNo();//包邮件数
        BigDecimal weightNo = termsInfoVO.getWeightNo();//包邮重量
        BigDecimal bulkNo = termsInfoVO.getBulkNo();//包邮体积
        BigDecimal price = termsInfoVO.getPrice();//包邮金额
        if (pieceNo!=null && quantity <pieceNo.intValue()){
            return true;
        }else if (weightNo!=null){
            BigDecimal weight = specificationVO.getWeight();
            if (weight!=null){
                BigDecimal totalWeight = new BigDecimal(quantity).multiply(weight).setScale(2);
                if (totalWeight.compareTo(weightNo) == -1){
                    return true;
                }
            }
        }else if(bulkNo!=null){
            BigDecimal volume = specificationVO.getVolume();
            if (volume!=null){
                BigDecimal totalWeight = new BigDecimal(quantity).multiply(volume).setScale(2);
                if (totalWeight.compareTo(bulkNo) == -1){
                    return true;
                }
            }
        }else if(price!=null){
            if (amount.compareTo(price) == 1){
                return true;
            }
        }
        return false;
    }

    /**
     * 检查周边是否满足包邮条件
     * @param quantity
     * @param amount
     */
    private void checkIsFree(FreeTemplateInfoVO templateInfoVO, Integer quantity, MallArticlesBuyVO articlesBuyVO, BigDecimal weight, BigDecimal volume, BigDecimal amount, Long addressId) {
        List<FreeDeliveryTermsInfoVO> delayedTerms = templateInfoVO.getDelayedTerms();
        Integer valuationModel = templateInfoVO.getValuationModel();
        if (CollectionUtils.isEmpty(delayedTerms)){
            throw new RuntimeException("缺少包邮条件！");
        }
        //省ID-市ID-区ID
        String str = addressService.selectInfoById(addressId);
        for (FreeDeliveryTermsInfoVO item : delayedTerms) {
            Long pieceNo = item.getPieceNo();//包邮件数
            BigDecimal weightNo = item.getWeightNo();//包邮重量
            BigDecimal bulkNo = item.getBulkNo();//包邮体积
            BigDecimal price = item.getPrice();//包邮金额
            if (FreeEnum.RADIUS.getDesc().equals(item.getRegion())){
                if (pieceNo!=null && quantity <pieceNo.intValue()){
                    articlesBuyVO.setIsFree(true);
                }else if (weightNo!=null){
                    if (weight!=null){
                        BigDecimal totalWeight = new BigDecimal(quantity).multiply(weight).setScale(2);
                        if (totalWeight.compareTo(weightNo) == -1){
                            articlesBuyVO.setIsFree(true);
                        }
                    }
                }else if(bulkNo!=null){
                    if (volume!=null){
                        BigDecimal totalWeight = new BigDecimal(quantity).multiply(volume).setScale(2);
                        if (totalWeight.compareTo(bulkNo) == -1){
                            articlesBuyVO.setIsFree(true);
                        }
                    }
                }else if(price!=null){
                    if (amount.compareTo(price) == 1){
                        articlesBuyVO.setIsFree(true);
                    }
                }
                if (articlesBuyVO.getIsFree()){
                    break;
                }
            }else {
                String addStr = item.getRegion();
                String[] split = addStr.split("\\|");
                List<String> asList = Arrays.asList(split);
                if (asList.contains(str)){
                    if (pieceNo!=null && quantity <pieceNo.intValue()){
                        articlesBuyVO.setIsFree(true);
                    }else if (weightNo!=null){
                        if (weight!=null){
                            BigDecimal totalWeight = new BigDecimal(quantity).multiply(weight).setScale(2);
                            if (totalWeight.compareTo(weightNo) == -1){
                                articlesBuyVO.setIsFree(true);
                            }
                        }
                    }else if(bulkNo!=null){
                        if (volume!=null){
                            BigDecimal totalWeight = new BigDecimal(quantity).multiply(volume).setScale(2);
                            if (totalWeight.compareTo(bulkNo) == -1){
                                articlesBuyVO.setIsFree(true);
                            }
                        }
                    }else if(price!=null){
                        if (amount.compareTo(price) == 1){
                            articlesBuyVO.setIsFree(true);
                        }
                    }
                    if (articlesBuyVO.getIsFree()){
                        break;
                    }
                }
            }
        }
    }

    /**
     * 计算并设置周边运费最小值
     * @param articlesBuyVO
     * @param addressId
     * @param quantity
     * @param specificationVO
     * @param templateInfoVO
     */
    private void setPeripheryFreePrice(MallArticlesBuyVO articlesBuyVO, Long addressId, Integer quantity, MallPeripherySpecificationVO specificationVO, FreeTemplateInfoVO templateInfoVO) {
        List<FreeCarryModeInfoVO> carryModeS = templateInfoVO.getCarryModeS();
        if (CollectionUtils.isEmpty(carryModeS)){//使用默认运费模板
            FreeCarryModeInfoVO carryModeInfoVO = templateService.selectDefultTempInfo();
            Integer valuationModel = templateInfoVO.getValuationModel();
            BigDecimal freePrice = getPeripheryFreePrice(quantity, specificationVO, carryModeInfoVO, valuationModel);
            articlesBuyVO.setFreePrice(freePrice);
        }else {//从地区中选择运费最便宜模板，选择最低运费
            //省ID-市ID-区ID
            String str = addressService.selectInfoById(addressId);
            Integer valuationModel = templateInfoVO.getValuationModel();
            BigDecimal freePrice = carryModeS.stream().filter(item->!"ALL".equals(item.getRegion())).filter(item -> item.getRegion().contains(str))
                    .map(item -> getPeripheryFreePrice(quantity, specificationVO, item, valuationModel))
                    .min(Comparator.naturalOrder()).orElse(null);
            if (freePrice==null){
                freePrice = carryModeS.stream().filter(item->"ALL".equals(item.getRegion()))
                        .map(item -> getPeripheryFreePrice(quantity, specificationVO, item, valuationModel))
                        .min(Comparator.naturalOrder()).orElse(null);
            }
            articlesBuyVO.setFreePrice(freePrice);
        }
    }

    /**
     * 计算书籍最小运费
     * @param articlesBuyVO
     * @param addressId
     * @param quantity
     * @param specificationVO
     * @param templateInfoVO
     */
    private void setBookFreePrice(MallArticlesBuyVO articlesBuyVO, Long addressId, Integer quantity, MallBooksSpecificationVO specificationVO, FreeTemplateInfoVO templateInfoVO) {
        List<FreeCarryModeInfoVO> carryModeS = templateInfoVO.getCarryModeS();
        if (CollectionUtils.isEmpty(carryModeS)){//使用默认运费模板
            FreeCarryModeInfoVO carryModeInfoVO = templateService.selectDefultTempInfo();
            Integer valuationModel = templateInfoVO.getValuationModel();
            BigDecimal freePrice = getBookFreePrice(quantity, specificationVO, carryModeInfoVO, valuationModel);
            articlesBuyVO.setFreePrice(freePrice);
        }else {//从地区中选择运费最便宜模板，选择最低运费
            //省ID-市ID-区ID
            String str = addressService.selectInfoById(addressId);
            Integer valuationModel = templateInfoVO.getValuationModel();
            BigDecimal freePrice = carryModeS.stream().filter(item->!"ALL".equals(item.getRegion())).filter(item -> item.getRegion().contains(str))
                    .map(item -> getBookFreePrice(quantity, specificationVO, item, valuationModel))
                    .min(Comparator.naturalOrder()).orElse(null);
            if (freePrice==null){
                freePrice = carryModeS.stream().filter(item->"ALL".equals(item.getRegion()))
                        .map(item -> getBookFreePrice(quantity, specificationVO, item, valuationModel))
                        .min(Comparator.naturalOrder()).orElse(null);
            }
            articlesBuyVO.setFreePrice(freePrice);
        }
    }

    private CommonCreateOrderResponse creatJDOrder(Integer num, String name, AddressDO addressDO, AtomicReference<BigDecimal> weight, AtomicReference<BigDecimal> volume, String logisticsOrderNum) {
        CreateOrderRequest createOrderRequest = new CreateOrderRequest();
        //商家物流订单编号
        createOrderRequest.setOrderId(logisticsOrderNum);
        AdminAddressDO adressDO = adminAddressService.lambdaQuery().one();
        Contact sender = new Contact();
        sender.setName(adressDO.getName());
        sender.setMobile(adressDO.getMobile());
        sender.setFullAddress(adressDO.getAddress());
        createOrderRequest.setSenderContact(sender);
        Contact receiver = new Contact();
        receiver.setName(addressDO.getReceiver());
        receiver.setMobile(addressDO.getMobile());
        receiver.setFullAddress(addressDO.getProvince()+addressDO.getCity()+addressDO.getArea()+addressDO.getDetail());
        createOrderRequest.setReceiverContact(receiver);

        createOrderRequest.setOrderOrigin(1);
        createOrderRequest.setCustomerCode(jdProperties.getCustomerCode());

        CommonProductInfo productInfo = new CommonProductInfo();
        productInfo.setProductCode("ed-m-0001");
        createOrderRequest.setProductsReq(productInfo);

        createOrderRequest.setSettleType(3);

        List<CommonCargoInfo> cargoInfos = Lists.newArrayList();
        CommonCargoInfo cargoInfo = new CommonCargoInfo();
        cargoInfo.setName(name);
        cargoInfo.setQuantity(num);
        cargoInfo.setWeight(weight.get());
        cargoInfo.setVolume(volume.get());
        cargoInfos.add(cargoInfo);
        createOrderRequest.setCargoes(cargoInfos);
        createOrderRequest.setRemark("");
        CommonCreateOrderResponse commonCreateOrderResponse = jdClient.create(createOrderRequest);
        return commonCreateOrderResponse;
    }

    private void jdPreCheck(AddressDO addressDO) {
        PreCheckRequest preCheckRequest = new PreCheckRequest();
        Contact sender = new Contact();
        sender.setFullAddress("河北省廊坊市广阳区万庄镇中心小学");
        preCheckRequest.setSenderContact(sender);

        Contact receiver = new Contact();
//        receiver.setFullAddress(addressDO.getProvince()+addressDO.getCity()+addressDO.getArea()+addressDO.getDetail());
        receiver.setFullAddress("河北省廊坊市广阳区万庄镇中心小学");
        preCheckRequest.setReceiverContact(receiver);

        preCheckRequest.setOrderOrigin(1);
        preCheckRequest.setCustomerCode(jdProperties.getCustomerCode());

        CommonProductInfo productInfo = new CommonProductInfo();
        productInfo.setProductCode("ed-m-0001");
        preCheckRequest.setProductsReq(productInfo);
        jdClient.preCheck(preCheckRequest);
    }

}